Skip to content

Commit d795679

Browse files
committed
Add explicit cid, probid, teamid to baloon table
to create a unique index. Also fixes baloons for rejudgings. fixes #2262
1 parent 44fcd06 commit d795679

File tree

4 files changed

+131
-16
lines changed

4 files changed

+131
-16
lines changed
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace DoctrineMigrations;
6+
7+
use Doctrine\DBAL\Schema\Schema;
8+
use Doctrine\Migrations\AbstractMigration;
9+
10+
/**
11+
* Auto-generated Migration: Please modify to your needs!
12+
*/
13+
final class Version20240322141105 extends AbstractMigration
14+
{
15+
public function getDescription(): string
16+
{
17+
return 'Add columns teamid, probid, cid and an uniq index with them to the baloon table.';
18+
}
19+
20+
public function up(Schema $schema): void
21+
{
22+
// this up() migration is auto-generated, please modify it to your needs
23+
24+
// remove dupicates
25+
$this->addSql('DELETE b FROM balloon as b LEFT JOIN (SELECT balloonid FROM balloon as b LEFT JOIN submission as s USING (submitid) GROUP BY teamid, probid, cid) as c ON(b.balloonid = c.balloonid) WHERE c.balloonid IS NULL');
26+
27+
$this->addSql('ALTER TABLE balloon ADD teamid INT UNSIGNED DEFAULT NULL COMMENT \'Team ID\', ADD probid INT UNSIGNED DEFAULT NULL COMMENT \'Problem ID\', ADD cid INT UNSIGNED DEFAULT NULL COMMENT \'Contest ID\'');
28+
$this->addSql('ALTER TABLE balloon ADD CONSTRAINT FK_643B3B904DD6ABF3 FOREIGN KEY (teamid) REFERENCES team (teamid) ON DELETE CASCADE');
29+
$this->addSql('ALTER TABLE balloon ADD CONSTRAINT FK_643B3B90EF049279 FOREIGN KEY (probid) REFERENCES problem (probid) ON DELETE CASCADE');
30+
$this->addSql('ALTER TABLE balloon ADD CONSTRAINT FK_643B3B904B30D9C4 FOREIGN KEY (cid) REFERENCES contest (cid) ON DELETE CASCADE');
31+
$this->addSql('CREATE INDEX IDX_643B3B904DD6ABF3 ON balloon (teamid)');
32+
$this->addSql('CREATE INDEX IDX_643B3B90EF049279 ON balloon (probid)');
33+
$this->addSql('CREATE INDEX IDX_643B3B904B30D9C4 ON balloon (cid)');
34+
$this->addSql('CREATE UNIQUE INDEX unique_problem ON balloon (cid, teamid, probid)');
35+
36+
// copy data
37+
$this->addSql('UPDATE balloon AS b JOIN submission AS s USING (submitid) SET b.teamid = s.teamid, b.probid = s.probid, b.cid = s.cid');
38+
}
39+
40+
public function down(Schema $schema): void
41+
{
42+
// this down() migration is auto-generated, please modify it to your needs
43+
$this->addSql('ALTER TABLE balloon DROP FOREIGN KEY FK_643B3B904DD6ABF3');
44+
$this->addSql('ALTER TABLE balloon DROP FOREIGN KEY FK_643B3B90EF049279');
45+
$this->addSql('ALTER TABLE balloon DROP FOREIGN KEY FK_643B3B904B30D9C4');
46+
$this->addSql('DROP INDEX IDX_643B3B904DD6ABF3 ON balloon');
47+
$this->addSql('DROP INDEX IDX_643B3B90EF049279 ON balloon');
48+
$this->addSql('DROP INDEX IDX_643B3B904B30D9C4 ON balloon');
49+
$this->addSql('DROP INDEX unique_problem ON balloon');
50+
$this->addSql('ALTER TABLE balloon DROP teamid, DROP probid, DROP cid');
51+
}
52+
53+
public function isTransactional(): bool
54+
{
55+
return false;
56+
}
57+
}

webapp/src/Entity/Balloon.php

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
namespace App\Entity;
33

44
use Doctrine\ORM\Mapping as ORM;
5+
use JMS\Serializer\Annotation as Serializer;
56

67
/**
78
* Balloons to be handed out.
@@ -13,6 +14,7 @@
1314
'comment' => 'Balloons to be handed out',
1415
])]
1516
#[ORM\Index(columns: ['submitid'], name: 'submitid')]
17+
#[ORM\UniqueConstraint(name: 'unique_problem', columns: ['cid', 'teamid', 'probid'])]
1618
class Balloon
1719
{
1820
#[ORM\Id]
@@ -27,6 +29,21 @@ class Balloon
2729
#[ORM\JoinColumn(name: 'submitid', referencedColumnName: 'submitid', onDelete: 'CASCADE')]
2830
private Submission $submission;
2931

32+
#[ORM\ManyToOne]
33+
#[ORM\JoinColumn(name: 'teamid', referencedColumnName: 'teamid', onDelete: 'CASCADE')]
34+
#[Serializer\Exclude]
35+
private Team $team;
36+
37+
#[ORM\ManyToOne]
38+
#[ORM\JoinColumn(name: 'probid', referencedColumnName: 'probid', onDelete: 'CASCADE')]
39+
#[Serializer\Exclude]
40+
private Problem $problem;
41+
42+
#[ORM\ManyToOne]
43+
#[ORM\JoinColumn(name: 'cid', referencedColumnName: 'cid', onDelete: 'CASCADE')]
44+
#[Serializer\Exclude]
45+
private Contest $contest;
46+
3047
public function getBalloonid(): int
3148
{
3249
return $this->balloonid;
@@ -53,4 +70,38 @@ public function getSubmission(): Submission
5370
{
5471
return $this->submission;
5572
}
73+
74+
public function getTeam(): Team
75+
{
76+
return $this->team;
77+
}
78+
79+
public function setTeam(Team $team): Balloon
80+
{
81+
$this->team = $team;
82+
return $this;
83+
}
84+
85+
public function getProblem(): Problem
86+
{
87+
return $this->problem;
88+
}
89+
90+
public function setProblem(Problem $problem): Balloon
91+
{
92+
$this->problem = $problem;
93+
return $this;
94+
}
95+
96+
public function getContest(): Contest
97+
{
98+
return $this->contest;
99+
}
100+
101+
public function setContest(Contest $contest): Balloon
102+
{
103+
$this->contest = $contest;
104+
return $this;
105+
}
106+
56107
}

webapp/src/Service/BalloonService.php

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
use App\Entity\Contest;
77
use App\Entity\ContestProblem;
88
use App\Entity\Judging;
9+
use App\Entity\Problem;
910
use App\Entity\ScoreCache;
1011
use App\Entity\Submission;
1112
use App\Entity\Team;
1213
use App\Entity\TeamAffiliation;
14+
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
1315
use Doctrine\ORM\EntityManagerInterface;
1416
use Doctrine\ORM\NonUniqueResultException;
1517
use Doctrine\ORM\NoResultException;
@@ -36,15 +38,15 @@ public function __construct(
3638
public function updateBalloons(
3739
Contest $contest,
3840
Submission $submission,
39-
?Judging $judging = null
41+
Judging $judging
4042
): void {
4143
// Balloon processing disabled for contest.
4244
if (!$contest->getProcessBalloons()) {
4345
return;
4446
}
4547

4648
// Make sure judging is correct.
47-
if (!$judging || $judging->getResult() !== Judging::RESULT_CORRECT) {
49+
if ($judging->getResult() !== Judging::RESULT_CORRECT) {
4850
return;
4951
}
5052

@@ -57,12 +59,10 @@ public function updateBalloons(
5759
// Prevent duplicate balloons in case of multiple correct submissions.
5860
$numCorrect = $this->em->createQueryBuilder()
5961
->from(Balloon::class, 'b')
60-
->join('b.submission', 's')
6162
->select('COUNT(b.submission) AS numBalloons')
62-
->andWhere('s.valid = 1')
63-
->andWhere('s.problem = :probid')
64-
->andWhere('s.team = :teamid')
65-
->andWhere('s.contest = :cid')
63+
->andWhere('b.problem = :probid')
64+
->andWhere('b.team = :teamid')
65+
->andWhere('b.contest = :cid')
6666
->setParameter('probid', $submission->getProblem())
6767
->setParameter('teamid', $submission->getTeam())
6868
->setParameter('cid', $submission->getContest())
@@ -71,10 +71,16 @@ public function updateBalloons(
7171

7272
if ($numCorrect == 0) {
7373
$balloon = new Balloon();
74-
$balloon->setSubmission(
75-
$this->em->getReference(Submission::class, $submission->getSubmitid()));
74+
$balloon->setSubmission($this->em->getReference(Submission::class, $submission->getSubmitid()));
75+
$balloon->setTeam($this->em->getReference(Team::class, $submission->getTeamId()));
76+
$balloon->setContest(
77+
$this->em->getReference(Contest::class, $submission->getContest()->getCid()));
78+
$balloon->setProblem($this->em->getReference(Problem::class, $submission->getProblemId()));
7679
$this->em->persist($balloon);
77-
$this->em->flush();
80+
try {
81+
$this->em->flush();
82+
} catch (UniqueConstraintViolationException $e) {
83+
}
7884
}
7985
}
8086

@@ -108,10 +114,10 @@ public function collectBalloonTable(Contest $contest, bool $todo = false): array
108114
'a.affilid AS affilid', 'a.shortname AS affilshort')
109115
->from(Balloon::class, 'b')
110116
->leftJoin('b.submission', 's')
111-
->leftJoin('s.problem', 'p')
112-
->leftJoin('s.contest', 'co')
117+
->leftJoin('b.problem', 'p')
118+
->leftJoin('b.contest', 'co')
113119
->leftJoin('p.contest_problems', 'cp', Join::WITH, 'co.cid = cp.contest AND p.probid = cp.problem')
114-
->leftJoin('s.team', 't')
120+
->leftJoin('b.team', 't')
115121
->leftJoin('t.category', 'c')
116122
->leftJoin('t.affiliation', 'a')
117123
->andWhere('co.cid = :cid')

webapp/src/Service/RejudgingService.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -277,9 +277,10 @@ public function finishRejudging(Rejudging $rejudging, string $action, ?callable
277277
}
278278

279279
// Update balloons.
280-
$contest = $this->em->getRepository(Contest::class)->find($submission['cid']);
281-
$submission = $this->em->getRepository(Submission::class)->find($submission['submitid']);
282-
$this->balloonService->updateBalloons($contest, $submission);
280+
$contest = $this->em->getRepository(Contest::class)->find($submission['cid']);
281+
$submissionEntity = $this->em->getRepository(Submission::class)->find($submission['submitid']);
282+
$judging = $this->em->getRepository(Judging::class)->find($submission['judgingid']);
283+
$this->balloonService->updateBalloons($contest, $submissionEntity, $judging);
283284
});
284285
} elseif ($action === self::ACTION_CANCEL) {
285286
// Reset submission and invalidate judging tasks.

0 commit comments

Comments
 (0)