Fix libpqxx 7.10.1 API compatibility

- Replace deprecated exec_params/exec_params0 calls with exec()
- Wrap all parameterized queries with pqxx::params{}
- Add .no_rows()/.one_row() to exec calls that don't return results
This commit is contained in:
Jörg Thalheim
2025-08-03 11:25:39 +02:00
committed by ahuston-0
parent 44b007c167
commit aee4e406e9
4 changed files with 87 additions and 117 deletions

View File

@@ -180,10 +180,8 @@ struct Evaluator
{ {
auto conn(dbPool.get()); auto conn(dbPool.get());
pqxx::work txn(*conn); pqxx::work txn(*conn);
txn.exec_params0 txn.exec("update Jobsets set startTime = $1 where id = $2",
("update Jobsets set startTime = $1 where id = $2", pqxx::params{now, jobset.name.id}).no_rows();
now,
jobset.name.id);
txn.commit(); txn.commit();
} }
@@ -234,7 +232,7 @@ struct Evaluator
pqxx::work txn(*conn); pqxx::work txn(*conn);
if (jobset.evaluation_style == EvaluationStyle::ONE_AT_A_TIME) { if (jobset.evaluation_style == EvaluationStyle::ONE_AT_A_TIME) {
auto evaluation_res = txn.exec_params auto evaluation_res = txn.exec
("select id from JobsetEvals " ("select id from JobsetEvals "
"where jobset_id = $1 " "where jobset_id = $1 "
"order by id desc limit 1" "order by id desc limit 1"
@@ -250,7 +248,7 @@ struct Evaluator
auto evaluation_id = evaluation_res[0][0].as<int>(); auto evaluation_id = evaluation_res[0][0].as<int>();
auto unfinished_build_res = txn.exec_params auto unfinished_build_res = txn.exec
("select id from Builds " ("select id from Builds "
"join JobsetEvalMembers " "join JobsetEvalMembers "
" on (JobsetEvalMembers.build = Builds.id) " " on (JobsetEvalMembers.build = Builds.id) "
@@ -420,21 +418,18 @@ struct Evaluator
/* Clear the trigger time to prevent this /* Clear the trigger time to prevent this
jobset from getting stuck in an endless jobset from getting stuck in an endless
failing eval loop. */ failing eval loop. */
txn.exec_params0 txn.exec
("update Jobsets set triggerTime = null where id = $1 and startTime is not null and triggerTime <= startTime", ("update Jobsets set triggerTime = null where id = $1 and startTime is not null and triggerTime <= startTime",
jobset.name.id); jobset.name.id).no_rows();
/* Clear the start time. */ /* Clear the start time. */
txn.exec_params0 txn.exec
("update Jobsets set startTime = null where id = $1", ("update Jobsets set startTime = null where id = $1",
jobset.name.id); jobset.name.id).no_rows();
if (!WIFEXITED(status) || WEXITSTATUS(status) > 1) { if (!WIFEXITED(status) || WEXITSTATUS(status) > 1) {
txn.exec_params0 txn.exec("update Jobsets set errorMsg = $1, lastCheckedTime = $2, errorTime = $2, fetchErrorMsg = null where id = $3",
("update Jobsets set errorMsg = $1, lastCheckedTime = $2, errorTime = $2, fetchErrorMsg = null where id = $3", pqxx::params{fmt("evaluation %s", statusToString(status)), now, jobset.name.id}).no_rows();
fmt("evaluation %s", statusToString(status)),
now,
jobset.name.id);
} }
txn.commit(); txn.commit();
@@ -459,7 +454,7 @@ struct Evaluator
{ {
auto conn(dbPool.get()); auto conn(dbPool.get());
pqxx::work txn(*conn); pqxx::work txn(*conn);
txn.exec("update Jobsets set startTime = null"); txn.exec("update Jobsets set startTime = null").no_rows();
txn.commit(); txn.commit();
} }

View File

@@ -458,13 +458,12 @@ void State::failStep(
for (auto & build : indirect) { for (auto & build : indirect) {
if (build->finishedInDB) continue; if (build->finishedInDB) continue;
printError("marking build %1% as failed", build->id); printError("marking build %1% as failed", build->id);
txn.exec_params0 txn.exec("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $4, isCachedBuild = $5, notificationPendingSince = $4 where id = $1 and finished = 0",
("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $4, isCachedBuild = $5, notificationPendingSince = $4 where id = $1 and finished = 0", pqxx::params{build->id,
build->id,
(int) (build->drvPath != step->drvPath && result.buildStatus() == bsFailed ? bsDepFailed : result.buildStatus()), (int) (build->drvPath != step->drvPath && result.buildStatus() == bsFailed ? bsDepFailed : result.buildStatus()),
result.startTime, result.startTime,
result.stopTime, result.stopTime,
result.stepStatus == bsCachedFailure ? 1 : 0); result.stepStatus == bsCachedFailure ? 1 : 0}).no_rows();
nrBuildsDone++; nrBuildsDone++;
} }
@@ -473,7 +472,7 @@ void State::failStep(
if (result.stepStatus != bsCachedFailure && result.canCache) if (result.stepStatus != bsCachedFailure && result.canCache)
for (auto & i : step->drv->outputsAndOptPaths(*localStore)) for (auto & i : step->drv->outputsAndOptPaths(*localStore))
if (i.second.second) if (i.second.second)
txn.exec_params0("insert into FailedPaths values ($1)", localStore->printStorePath(*i.second.second)); txn.exec("insert into FailedPaths values ($1)", pqxx::params{localStore->printStorePath(*i.second.second)}).no_rows();
txn.commit(); txn.commit();
} }

View File

@@ -276,17 +276,16 @@ void State::monitorMachinesFile()
void State::clearBusy(Connection & conn, time_t stopTime) void State::clearBusy(Connection & conn, time_t stopTime)
{ {
pqxx::work txn(conn); pqxx::work txn(conn);
txn.exec_params0 txn.exec("update BuildSteps set busy = 0, status = $1, stopTime = $2 where busy != 0",
("update BuildSteps set busy = 0, status = $1, stopTime = $2 where busy != 0", pqxx::params{(int) bsAborted,
(int) bsAborted, stopTime != 0 ? std::make_optional(stopTime) : std::nullopt}).no_rows();
stopTime != 0 ? std::make_optional(stopTime) : std::nullopt);
txn.commit(); txn.commit();
} }
unsigned int State::allocBuildStep(pqxx::work & txn, BuildID buildId) unsigned int State::allocBuildStep(pqxx::work & txn, BuildID buildId)
{ {
auto res = txn.exec_params1("select max(stepnr) from BuildSteps where build = $1", buildId); auto res = txn.exec("select max(stepnr) from BuildSteps where build = $1", buildId).one_row();
return res[0].is_null() ? 1 : res[0].as<int>() + 1; return res[0].is_null() ? 1 : res[0].as<int>() + 1;
} }
@@ -297,9 +296,8 @@ unsigned int State::createBuildStep(pqxx::work & txn, time_t startTime, BuildID
restart: restart:
auto stepNr = allocBuildStep(txn, buildId); auto stepNr = allocBuildStep(txn, buildId);
auto r = txn.exec_params auto r = txn.exec("insert into BuildSteps (build, stepnr, type, drvPath, busy, startTime, system, status, propagatedFrom, errorMsg, stopTime, machine) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) on conflict do nothing",
("insert into BuildSteps (build, stepnr, type, drvPath, busy, startTime, system, status, propagatedFrom, errorMsg, stopTime, machine) values ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) on conflict do nothing", pqxx::params{buildId,
buildId,
stepNr, stepNr,
0, // == build 0, // == build
localStore->printStorePath(step->drvPath), localStore->printStorePath(step->drvPath),
@@ -310,17 +308,16 @@ unsigned int State::createBuildStep(pqxx::work & txn, time_t startTime, BuildID
propagatedFrom != 0 ? std::make_optional(propagatedFrom) : std::nullopt, // internal::params propagatedFrom != 0 ? std::make_optional(propagatedFrom) : std::nullopt, // internal::params
errorMsg != "" ? std::make_optional(errorMsg) : std::nullopt, errorMsg != "" ? std::make_optional(errorMsg) : std::nullopt,
startTime != 0 && status != bsBusy ? std::make_optional(startTime) : std::nullopt, startTime != 0 && status != bsBusy ? std::make_optional(startTime) : std::nullopt,
machine); machine});
if (r.affected_rows() == 0) goto restart; if (r.affected_rows() == 0) goto restart;
for (auto & [name, output] : getDestStore()->queryPartialDerivationOutputMap(step->drvPath, &*localStore)) for (auto & [name, output] : getDestStore()->queryPartialDerivationOutputMap(step->drvPath, &*localStore))
txn.exec_params0 txn.exec("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)",
("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)", pqxx::params{buildId, stepNr, name,
buildId, stepNr, name,
output output
? std::optional { localStore->printStorePath(*output)} ? std::optional { localStore->printStorePath(*output)}
: std::nullopt); : std::nullopt}).no_rows();
if (status == bsBusy) if (status == bsBusy)
txn.exec(fmt("notify step_started, '%d\t%d'", buildId, stepNr)); txn.exec(fmt("notify step_started, '%d\t%d'", buildId, stepNr));
@@ -331,11 +328,10 @@ unsigned int State::createBuildStep(pqxx::work & txn, time_t startTime, BuildID
void State::updateBuildStep(pqxx::work & txn, BuildID buildId, unsigned int stepNr, StepState stepState) void State::updateBuildStep(pqxx::work & txn, BuildID buildId, unsigned int stepNr, StepState stepState)
{ {
if (txn.exec_params if (txn.exec("update BuildSteps set busy = $1 where build = $2 and stepnr = $3 and busy != 0 and status is null",
("update BuildSteps set busy = $1 where build = $2 and stepnr = $3 and busy != 0 and status is null", pqxx::params{(int) stepState,
(int) stepState,
buildId, buildId,
stepNr).affected_rows() != 1) stepNr}).affected_rows() != 1)
throw Error("step %d of build %d is in an unexpected state", stepNr, buildId); throw Error("step %d of build %d is in an unexpected state", stepNr, buildId);
} }
@@ -345,29 +341,27 @@ void State::finishBuildStep(pqxx::work & txn, const RemoteResult & result,
{ {
assert(result.startTime); assert(result.startTime);
assert(result.stopTime); assert(result.stopTime);
txn.exec_params0 txn.exec("update BuildSteps set busy = 0, status = $1, errorMsg = $4, startTime = $5, stopTime = $6, machine = $7, overhead = $8, timesBuilt = $9, isNonDeterministic = $10 where build = $2 and stepnr = $3",
("update BuildSteps set busy = 0, status = $1, errorMsg = $4, startTime = $5, stopTime = $6, machine = $7, overhead = $8, timesBuilt = $9, isNonDeterministic = $10 where build = $2 and stepnr = $3", pqxx::params{(int) result.stepStatus, buildId, stepNr,
(int) result.stepStatus, buildId, stepNr,
result.errorMsg != "" ? std::make_optional(result.errorMsg) : std::nullopt, result.errorMsg != "" ? std::make_optional(result.errorMsg) : std::nullopt,
result.startTime, result.stopTime, result.startTime, result.stopTime,
machine != "" ? std::make_optional(machine) : std::nullopt, machine != "" ? std::make_optional(machine) : std::nullopt,
result.overhead != 0 ? std::make_optional(result.overhead) : std::nullopt, result.overhead != 0 ? std::make_optional(result.overhead) : std::nullopt,
result.timesBuilt > 0 ? std::make_optional(result.timesBuilt) : std::nullopt, result.timesBuilt > 0 ? std::make_optional(result.timesBuilt) : std::nullopt,
result.timesBuilt > 1 ? std::make_optional(result.isNonDeterministic) : std::nullopt); result.timesBuilt > 1 ? std::make_optional(result.isNonDeterministic) : std::nullopt}).no_rows();
assert(result.logFile.find('\t') == std::string::npos); assert(result.logFile.find('\t') == std::string::npos);
txn.exec(fmt("notify step_finished, '%d\t%d\t%s'", txn.exec(fmt("notify step_finished, '%d\t%d\t%s'",
buildId, stepNr, result.logFile)); buildId, stepNr, result.logFile));
if (result.stepStatus == bsSuccess) { if (result.stepStatus == bsSuccess) {
// Update the corresponding `BuildStepOutputs` row to add the output path // Update the corresponding `BuildStepOutputs` row to add the output path
auto res = txn.exec_params1("select drvPath from BuildSteps where build = $1 and stepnr = $2", buildId, stepNr); auto res = txn.exec("select drvPath from BuildSteps where build = $1 and stepnr = $2", pqxx::params{buildId, stepNr}).one_row();
assert(res.size()); assert(res.size());
StorePath drvPath = localStore->parseStorePath(res[0].as<std::string>()); StorePath drvPath = localStore->parseStorePath(res[0].as<std::string>());
// If we've finished building, all the paths should be known // If we've finished building, all the paths should be known
for (auto & [name, output] : getDestStore()->queryDerivationOutputMap(drvPath, &*localStore)) for (auto & [name, output] : getDestStore()->queryDerivationOutputMap(drvPath, &*localStore))
txn.exec_params0 txn.exec("update BuildStepOutputs set path = $4 where build = $1 and stepnr = $2 and name = $3",
("update BuildStepOutputs set path = $4 where build = $1 and stepnr = $2 and name = $3", pqxx::params{buildId, stepNr, name, localStore->printStorePath(output)}).no_rows();
buildId, stepNr, name, localStore->printStorePath(output));
} }
} }
@@ -378,23 +372,21 @@ int State::createSubstitutionStep(pqxx::work & txn, time_t startTime, time_t sto
restart: restart:
auto stepNr = allocBuildStep(txn, build->id); auto stepNr = allocBuildStep(txn, build->id);
auto r = txn.exec_params auto r = txn.exec("insert into BuildSteps (build, stepnr, type, drvPath, busy, status, startTime, stopTime) values ($1, $2, $3, $4, $5, $6, $7, $8) on conflict do nothing",
("insert into BuildSteps (build, stepnr, type, drvPath, busy, status, startTime, stopTime) values ($1, $2, $3, $4, $5, $6, $7, $8) on conflict do nothing", pqxx::params{build->id,
build->id,
stepNr, stepNr,
1, // == substitution 1, // == substitution
(localStore->printStorePath(drvPath)), (localStore->printStorePath(drvPath)),
0, 0,
0, 0,
startTime, startTime,
stopTime); stopTime});
if (r.affected_rows() == 0) goto restart; if (r.affected_rows() == 0) goto restart;
txn.exec_params0 txn.exec("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)",
("insert into BuildStepOutputs (build, stepnr, name, path) values ($1, $2, $3, $4)", pqxx::params{build->id, stepNr, outputName,
build->id, stepNr, outputName, localStore->printStorePath(storePath)}).no_rows();
localStore->printStorePath(storePath));
return stepNr; return stepNr;
} }
@@ -461,35 +453,32 @@ void State::markSucceededBuild(pqxx::work & txn, Build::ptr build,
{ {
if (build->finishedInDB) return; if (build->finishedInDB) return;
if (txn.exec_params("select 1 from Builds where id = $1 and finished = 0", build->id).empty()) return; if (txn.exec("select 1 from Builds where id = $1 and finished = 0", pqxx::params{build->id}).empty()) return;
txn.exec_params0 txn.exec("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $4, size = $5, closureSize = $6, releaseName = $7, isCachedBuild = $8, notificationPendingSince = $4 where id = $1",
("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $4, size = $5, closureSize = $6, releaseName = $7, isCachedBuild = $8, notificationPendingSince = $4 where id = $1", pqxx::params{build->id,
build->id,
(int) (res.failed ? bsFailedWithOutput : bsSuccess), (int) (res.failed ? bsFailedWithOutput : bsSuccess),
startTime, startTime,
stopTime, stopTime,
res.size, res.size,
res.closureSize, res.closureSize,
res.releaseName != "" ? std::make_optional(res.releaseName) : std::nullopt, res.releaseName != "" ? std::make_optional(res.releaseName) : std::nullopt,
isCachedBuild ? 1 : 0); isCachedBuild ? 1 : 0}).no_rows();
for (auto & [outputName, outputPath] : res.outputs) { for (auto & [outputName, outputPath] : res.outputs) {
txn.exec_params0 txn.exec("update BuildOutputs set path = $3 where build = $1 and name = $2",
("update BuildOutputs set path = $3 where build = $1 and name = $2", pqxx::params{build->id,
build->id,
outputName, outputName,
localStore->printStorePath(outputPath) localStore->printStorePath(outputPath)}
); ).no_rows();
} }
txn.exec_params0("delete from BuildProducts where build = $1", build->id); txn.exec("delete from BuildProducts where build = $1", pqxx::params{build->id}).no_rows();
unsigned int productNr = 1; unsigned int productNr = 1;
for (auto & product : res.products) { for (auto & product : res.products) {
txn.exec_params0 txn.exec("insert into BuildProducts (build, productnr, type, subtype, fileSize, sha256hash, path, name, defaultPath) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
("insert into BuildProducts (build, productnr, type, subtype, fileSize, sha256hash, path, name, defaultPath) values ($1, $2, $3, $4, $5, $6, $7, $8, $9)", pqxx::params{build->id,
build->id,
productNr++, productNr++,
product.type, product.type,
product.subtype, product.subtype,
@@ -497,22 +486,21 @@ void State::markSucceededBuild(pqxx::work & txn, Build::ptr build,
product.sha256hash ? std::make_optional(product.sha256hash->to_string(HashFormat::Base16, false)) : std::nullopt, product.sha256hash ? std::make_optional(product.sha256hash->to_string(HashFormat::Base16, false)) : std::nullopt,
product.path, product.path,
product.name, product.name,
product.defaultPath); product.defaultPath}).no_rows();
} }
txn.exec_params0("delete from BuildMetrics where build = $1", build->id); txn.exec("delete from BuildMetrics where build = $1", pqxx::params{build->id}).no_rows();
for (auto & metric : res.metrics) { for (auto & metric : res.metrics) {
txn.exec_params0 txn.exec("insert into BuildMetrics (build, name, unit, value, project, jobset, job, timestamp) values ($1, $2, $3, $4, $5, $6, $7, $8)",
("insert into BuildMetrics (build, name, unit, value, project, jobset, job, timestamp) values ($1, $2, $3, $4, $5, $6, $7, $8)", pqxx::params{build->id,
build->id,
metric.second.name, metric.second.name,
metric.second.unit != "" ? std::make_optional(metric.second.unit) : std::nullopt, metric.second.unit != "" ? std::make_optional(metric.second.unit) : std::nullopt,
metric.second.value, metric.second.value,
build->projectName, build->projectName,
build->jobsetName, build->jobsetName,
build->jobName, build->jobName,
build->timestamp); build->timestamp}).no_rows();
} }
nrBuildsDone++; nrBuildsDone++;
@@ -524,7 +512,7 @@ bool State::checkCachedFailure(Step::ptr step, Connection & conn)
pqxx::work txn(conn); pqxx::work txn(conn);
for (auto & i : step->drv->outputsAndOptPaths(*localStore)) for (auto & i : step->drv->outputsAndOptPaths(*localStore))
if (i.second.second) if (i.second.second)
if (!txn.exec_params("select 1 from FailedPaths where path = $1", localStore->printStorePath(*i.second.second)).empty()) if (!txn.exec("select 1 from FailedPaths where path = $1", pqxx::params{localStore->printStorePath(*i.second.second)}).empty())
return true; return true;
return false; return false;
} }
@@ -736,8 +724,8 @@ void State::dumpStatus(Connection & conn)
auto mc = startDbUpdate(); auto mc = startDbUpdate();
pqxx::work txn(conn); pqxx::work txn(conn);
// FIXME: use PostgreSQL 9.5 upsert. // FIXME: use PostgreSQL 9.5 upsert.
txn.exec("delete from SystemStatus where what = 'queue-runner'"); txn.exec("delete from SystemStatus where what = 'queue-runner'").no_rows();
txn.exec_params0("insert into SystemStatus values ('queue-runner', $1)", statusJson.dump()); txn.exec("insert into SystemStatus values ('queue-runner', $1)", pqxx::params{statusJson.dump()}).no_rows();
txn.exec("notify status_dumped"); txn.exec("notify status_dumped");
txn.commit(); txn.commit();
} }
@@ -802,7 +790,7 @@ void State::unlock()
{ {
pqxx::work txn(*conn); pqxx::work txn(*conn);
txn.exec("delete from SystemStatus where what = 'queue-runner'"); txn.exec("delete from SystemStatus where what = 'queue-runner'").no_rows();
txn.commit(); txn.commit();
} }
} }
@@ -880,11 +868,10 @@ void State::run(BuildID buildOne)
pqxx::work txn(*conn); pqxx::work txn(*conn);
for (auto & step : steps) { for (auto & step : steps) {
printMsg(lvlError, "cleaning orphaned step %d of build %d", step.second, step.first); printMsg(lvlError, "cleaning orphaned step %d of build %d", step.second, step.first);
txn.exec_params0 txn.exec("update BuildSteps set busy = 0, status = $1 where build = $2 and stepnr = $3 and busy != 0",
("update BuildSteps set busy = 0, status = $1 where build = $2 and stepnr = $3 and busy != 0", pqxx::params{(int) bsAborted,
(int) bsAborted,
step.first, step.first,
step.second); step.second}).no_rows();
} }
txn.commit(); txn.commit();
} catch (std::exception & e) { } catch (std::exception & e) {

View File

@@ -108,8 +108,7 @@ bool State::getQueuedBuilds(Connection & conn,
{ {
pqxx::work txn(conn); pqxx::work txn(conn);
auto res = txn.exec_params auto res = txn.exec("select builds.id, builds.jobset_id, jobsets.project as project, "
("select builds.id, builds.jobset_id, jobsets.project as project, "
"jobsets.name as jobset, job, drvPath, maxsilent, timeout, timestamp, " "jobsets.name as jobset, job, drvPath, maxsilent, timeout, timestamp, "
"globalPriority, priority from Builds " "globalPriority, priority from Builds "
"inner join jobsets on builds.jobset_id = jobsets.id " "inner join jobsets on builds.jobset_id = jobsets.id "
@@ -158,11 +157,10 @@ bool State::getQueuedBuilds(Connection & conn,
if (!build->finishedInDB) { if (!build->finishedInDB) {
auto mc = startDbUpdate(); auto mc = startDbUpdate();
pqxx::work txn(conn); pqxx::work txn(conn);
txn.exec_params0 txn.exec("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3 where id = $1 and finished = 0",
("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3 where id = $1 and finished = 0", pqxx::params{build->id,
build->id,
(int) bsAborted, (int) bsAborted,
time(0)); time(0)}).no_rows();
txn.commit(); txn.commit();
build->finishedInDB = true; build->finishedInDB = true;
nrBuildsDone++; nrBuildsDone++;
@@ -192,22 +190,20 @@ bool State::getQueuedBuilds(Connection & conn,
derivation path, then by output path. */ derivation path, then by output path. */
BuildID propagatedFrom = 0; BuildID propagatedFrom = 0;
auto res = txn.exec_params1 auto res = txn.exec("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1",
("select max(build) from BuildSteps where drvPath = $1 and startTime != 0 and stopTime != 0 and status = 1", pqxx::params{localStore->printStorePath(ex.step->drvPath)}).one_row();
localStore->printStorePath(ex.step->drvPath));
if (!res[0].is_null()) propagatedFrom = res[0].as<BuildID>(); if (!res[0].is_null()) propagatedFrom = res[0].as<BuildID>();
if (!propagatedFrom) { if (!propagatedFrom) {
for (auto & [outputName, optOutputPath] : destStore->queryPartialDerivationOutputMap(ex.step->drvPath, &*localStore)) { for (auto & [outputName, optOutputPath] : destStore->queryPartialDerivationOutputMap(ex.step->drvPath, &*localStore)) {
constexpr std::string_view common = "select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where startTime != 0 and stopTime != 0 and status = 1"; constexpr std::string_view common = "select max(s.build) from BuildSteps s join BuildStepOutputs o on s.build = o.build where startTime != 0 and stopTime != 0 and status = 1";
auto res = optOutputPath auto res = optOutputPath
? txn.exec_params( ? txn.exec(
std::string { common } + " and path = $1", std::string { common } + " and path = $1",
localStore->printStorePath(*optOutputPath)) pqxx::params{localStore->printStorePath(*optOutputPath)})
: txn.exec_params( : txn.exec(
std::string { common } + " and drvPath = $1 and name = $2", std::string { common } + " and drvPath = $1 and name = $2",
localStore->printStorePath(ex.step->drvPath), pqxx::params{localStore->printStorePath(ex.step->drvPath), outputName});
outputName);
if (!res[0][0].is_null()) { if (!res[0][0].is_null()) {
propagatedFrom = res[0][0].as<BuildID>(); propagatedFrom = res[0][0].as<BuildID>();
break; break;
@@ -216,12 +212,11 @@ bool State::getQueuedBuilds(Connection & conn,
} }
createBuildStep(txn, 0, build->id, ex.step, "", bsCachedFailure, "", propagatedFrom); createBuildStep(txn, 0, build->id, ex.step, "", bsCachedFailure, "", propagatedFrom);
txn.exec_params txn.exec("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = 1, notificationPendingSince = $3 "
("update Builds set finished = 1, buildStatus = $2, startTime = $3, stopTime = $3, isCachedBuild = 1, notificationPendingSince = $3 "
"where id = $1 and finished = 0", "where id = $1 and finished = 0",
build->id, pqxx::params{build->id,
(int) (ex.step->drvPath == build->drvPath ? bsFailed : bsDepFailed), (int) (ex.step->drvPath == build->drvPath ? bsFailed : bsDepFailed),
time(0)); time(0)}).no_rows();
notifyBuildFinished(txn, build->id, {}); notifyBuildFinished(txn, build->id, {});
txn.commit(); txn.commit();
build->finishedInDB = true; build->finishedInDB = true;
@@ -653,10 +648,8 @@ Jobset::ptr State::createJobset(pqxx::work & txn,
if (i != jobsets_->end()) return i->second; if (i != jobsets_->end()) return i->second;
} }
auto res = txn.exec_params1 auto res = txn.exec("select schedulingShares from Jobsets where id = $1",
("select schedulingShares from Jobsets where id = $1", pqxx::params{jobsetID}).one_row();
jobsetID);
if (res.empty()) throw Error("missing jobset - can't happen");
auto shares = res["schedulingShares"].as<unsigned int>(); auto shares = res["schedulingShares"].as<unsigned int>();
@@ -664,11 +657,10 @@ Jobset::ptr State::createJobset(pqxx::work & txn,
jobset->setShares(shares); jobset->setShares(shares);
/* Load the build steps from the last 24 hours. */ /* Load the build steps from the last 24 hours. */
auto res2 = txn.exec_params auto res2 = txn.exec("select s.startTime, s.stopTime from BuildSteps s join Builds b on build = id "
("select s.startTime, s.stopTime from BuildSteps s join Builds b on build = id "
"where s.startTime is not null and s.stopTime > $1 and jobset_id = $2", "where s.startTime is not null and s.stopTime > $1 and jobset_id = $2",
time(0) - Jobset::schedulingWindow * 10, pqxx::params{time(0) - Jobset::schedulingWindow * 10,
jobsetID); jobsetID});
for (auto const & row : res2) { for (auto const & row : res2) {
time_t startTime = row["startTime"].as<time_t>(); time_t startTime = row["startTime"].as<time_t>();
time_t stopTime = row["stopTime"].as<time_t>(); time_t stopTime = row["stopTime"].as<time_t>();
@@ -705,11 +697,10 @@ BuildOutput State::getBuildOutputCached(Connection & conn, nix::ref<nix::Store>
pqxx::work txn(conn); pqxx::work txn(conn);
for (auto & [name, output] : derivationOutputs) { for (auto & [name, output] : derivationOutputs) {
auto r = txn.exec_params auto r = txn.exec("select id, buildStatus, releaseName, closureSize, size from Builds b "
("select id, buildStatus, releaseName, closureSize, size from Builds b "
"join BuildOutputs o on b.id = o.build " "join BuildOutputs o on b.id = o.build "
"where finished = 1 and (buildStatus = 0 or buildStatus = 6) and path = $1", "where finished = 1 and (buildStatus = 0 or buildStatus = 6) and path = $1",
localStore->printStorePath(output)); pqxx::params{localStore->printStorePath(output)});
if (r.empty()) continue; if (r.empty()) continue;
BuildID id = r[0][0].as<BuildID>(); BuildID id = r[0][0].as<BuildID>();
@@ -721,9 +712,8 @@ BuildOutput State::getBuildOutputCached(Connection & conn, nix::ref<nix::Store>
res.closureSize = r[0][3].is_null() ? 0 : r[0][3].as<uint64_t>(); res.closureSize = r[0][3].is_null() ? 0 : r[0][3].as<uint64_t>();
res.size = r[0][4].is_null() ? 0 : r[0][4].as<uint64_t>(); res.size = r[0][4].is_null() ? 0 : r[0][4].as<uint64_t>();
auto products = txn.exec_params auto products = txn.exec("select type, subtype, fileSize, sha256hash, path, name, defaultPath from BuildProducts where build = $1 order by productnr",
("select type, subtype, fileSize, sha256hash, path, name, defaultPath from BuildProducts where build = $1 order by productnr", pqxx::params{id});
id);
for (auto row : products) { for (auto row : products) {
BuildProduct product; BuildProduct product;
@@ -745,9 +735,8 @@ BuildOutput State::getBuildOutputCached(Connection & conn, nix::ref<nix::Store>
res.products.emplace_back(product); res.products.emplace_back(product);
} }
auto metrics = txn.exec_params auto metrics = txn.exec("select name, unit, value from BuildMetrics where build = $1",
("select name, unit, value from BuildMetrics where build = $1", pqxx::params{id});
id);
for (auto row : metrics) { for (auto row : metrics) {
BuildMetric metric; BuildMetric metric;