function do_setting_update($sv)
{
    global $Conf, $Group, $Me, $Now, $Opt, $OptOverride;
    // parse settings
    foreach (Si::$all as $si) {
        account_value($sv, $si);
    }
    // check date relationships
    foreach (array("sub_reg" => "sub_sub", "final_soft" => "final_done") as $dn1 => $dn2) {
        list($dv1, $dv2) = [$sv->savedv($dn1), $sv->savedv($dn2)];
    }
    if (!$dv1 && $dv2) {
        $sv->save($dn1, $dv2);
    } else {
        if ($dv2 && $dv1 > $dv2) {
            $sv->set_error($dn1, unparse_setting_error(Si::get($dn1), "Must come before " . Si::get($dn2, "short_description") . "."));
            $sv->set_error($dn2);
        }
    }
    if ($sv->has_savedv("sub_sub")) {
        $sv->save("sub_update", $sv->savedv("sub_sub"));
    }
    if (get($Opt, "defaultSiteContact")) {
        if ($sv->has_savedv("opt.contactName") && get($Opt, "contactName") === $sv->savedv("opt.contactName")) {
            $sv->save("opt.contactName", null);
        }
        if ($sv->has_savedv("opt.contactEmail") && get($Opt, "contactEmail") === $sv->savedv("opt.contactEmail")) {
            $sv->save("opt.contactEmail", null);
        }
    }
    if ($sv->has_savedv("resp_active") && $sv->savedv("resp_active")) {
        foreach (explode(" ", $sv->newv("resp_rounds")) as $i => $rname) {
            $isuf = $i ? "_{$i}" : "";
            if ($sv->newv("resp_open{$isuf}") > $sv->newv("resp_done{$isuf}")) {
                $sv->set_error("resp_open{$isuf}", unparse_setting_error(Si::get("resp_open"), "Must come before " . Si::get("resp_done", "short_description") . "."));
                $sv->set_error("resp_done{$isuf}");
            }
        }
    }
    // update 'papersub'
    if ($sv->has_savedv("pc_seeall")) {
        // see also conference.php
        if ($sv->savedv("pc_seeall") <= 0) {
            $x = "timeSubmitted>0";
        } else {
            $x = "timeWithdrawn<=0";
        }
        $num = Dbl::fetch_ivalue("select paperId from Paper where {$x} limit 1") ? 1 : 0;
        if ($num != $Conf->setting("papersub")) {
            $sv->save("papersub", $num);
        }
    }
    // Setting relationships
    if ($sv->has_savedv("sub_open") && $sv->newv("sub_open", 1) <= 0 && $sv->oldv("sub_open") > 0 && $sv->newv("sub_sub") <= 0) {
        $sv->save("sub_close", $Now);
    }
    if ($sv->has_savedv("msg.clickthrough_submit")) {
        $sv->save("clickthrough_submit", null);
    }
    // make settings
    $changedn = [];
    if (!$sv->has_errors() && (count($sv->savedv) || count($sv->save_callbacks))) {
        $tables = "Settings write";
        foreach ($sv->need_lock as $t => $need) {
            if ($need) {
                $tables .= ", {$t} write";
            }
        }
        $Conf->qe("lock tables {$tables}");
        // load db settings, pre-crosscheck
        $dbsettings = array();
        $result = Dbl::qe("select name, value, data from Settings");
        while ($row = edb_row($result)) {
            $dbsettings[$row[0]] = $row;
        }
        Dbl::free($result);
        // apply settings
        foreach ($sv->save_callbacks as $si) {
            $p = $sv->parser($si);
            $p->save($sv, $si);
        }
        $dv = $aq = $av = array();
        foreach ($sv->savedv as $n => $v) {
            if (substr($n, 0, 4) === "opt." && $v !== null) {
                $okey = substr($n, 4);
                $oldv = array_key_exists($okey, $OptOverride) ? $OptOverride[$okey] : get($Opt, $okey);
                $Opt[$okey] = $v[1] === null ? $v[0] : $v[1];
                if ($oldv === $Opt[$okey]) {
                    $v = null;
                } else {
                    if (!array_key_exists($okey, $OptOverride)) {
                        $OptOverride[$okey] = $oldv;
                    }
                }
            }
            if ($v === null ? !isset($dbsettings[$n]) : isset($dbsettings[$n]) && (int) $dbsettings[$n][1] === $v[0] && $dbsettings[$n][2] === $v[1]) {
                continue;
            }
            $changedn[] = $n;
            if ($v !== null) {
                $aq[] = "(?, ?, ?)";
                array_push($av, $n, $v[0], $v[1]);
            } else {
                $dv[] = $n;
            }
        }
        if (count($dv)) {
            Dbl::qe_apply("delete from Settings where name?a", array($dv));
            //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query_apply("delete from Settings where name?a", array($dv))));
        }
        if (count($aq)) {
            Dbl::qe_apply("insert into Settings (name, value, data) values\n\t" . join(",\n\t", $aq) . "\n\ton duplicate key update value=values(value), data=values(data)", $av);
            //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query_apply("insert into Settings (name, value, data) values\n\t" . join(",\n\t", $aq) . "\n\ton duplicate key update value=values(value), data=values(data)", $av)));
        }
        $Conf->qe("unlock tables");
        if (count($changedn)) {
            $Me->log_activity("Updated settings " . join(", ", $changedn));
        }
        $Conf->load_settings();
        // contactdb may need to hear about changes to shortName
        if ($sv->has_savedv("opt.shortName") && get($Opt, "contactdb_dsn") && ($cdb = Contact::contactdb())) {
            Dbl::ql($cdb, "update Conferences set shortName=? where dbName=?", $Opt["shortName"], $Opt["dbName"]);
        }
    }
    // update the review form in case it's changed
    ReviewForm::clear_cache();
    if (!$sv->has_errors()) {
        $Conf->save_session("settings_highlight", $sv->error_fields());
        if (count($changedn)) {
            $Conf->confirmMsg("Changes saved.");
        } else {
            $Conf->warnMsg("No changes.");
        }
        $sv->report();
        redirectSelf();
    } else {
        SettingGroup::crosscheck($sv, $Group);
        $sv->report();
    }
}
 function invalidateCaches($caches = null)
 {
     global $OK;
     if (self::$no_invalidate_caches) {
         return;
     }
     $inserts = array();
     $removes = array();
     $time = time();
     if ($caches ? isset($caches["pc"]) : $this->setting("pc") > 0) {
         if (!$caches || $caches["pc"]) {
             $inserts[] = "('pc',{$time})";
             $this->settings["pc"] = $time;
         } else {
             $removes[] = "'pc'";
             unset($this->settings["pc"]);
         }
     }
     if (!$caches || isset($caches["paperOption"])) {
         PaperOption::invalidate_option_list();
     }
     if (!$caches || isset($caches["rf"])) {
         ReviewForm::clear_cache();
         $this->_defined_rounds = null;
     }
     $ok = true;
     if (count($inserts)) {
         $ok = $ok && $this->qe("insert into Settings (name, value) values " . join(",", $inserts) . " on duplicate key update value=values(value)") !== false;
     }
     if (count($removes)) {
         $ok = $ok && $this->qe("delete from Settings where name in (" . join(",", $removes) . ")") !== false;
     }
     return $ok;
 }