Add support for OF in row lock clauses

This adds support for statements such as `SELECT ... FOR UPDATE OF table NOWAIT` where `OF table`
could not be specified previously. Fixes #285.
This commit is contained in:
Matthew Dowdell 2023-11-30 07:52:54 +00:00
parent 6a13530ec1
commit f16f0b5e5d
4 changed files with 48 additions and 1 deletions

View file

@ -4,12 +4,14 @@ package jet
type RowLock interface { type RowLock interface {
Serializer Serializer
OF(...Table) RowLock
NOWAIT() RowLock NOWAIT() RowLock
SKIP_LOCKED() RowLock SKIP_LOCKED() RowLock
} }
type selectLockImpl struct { type selectLockImpl struct {
lockStrength string lockStrength string
of []Table
noWait, skipLocked bool noWait, skipLocked bool
} }
@ -20,10 +22,15 @@ func NewRowLock(name string) func() RowLock {
} }
} }
func newSelectLock(lockStrength string) RowLock { func newSelectLock(lockStrength string) *selectLockImpl {
return &selectLockImpl{lockStrength: lockStrength} return &selectLockImpl{lockStrength: lockStrength}
} }
func (s *selectLockImpl) OF(tables ...Table) RowLock {
s.of = tables
return s
}
func (s *selectLockImpl) NOWAIT() RowLock { func (s *selectLockImpl) NOWAIT() RowLock {
s.noWait = true s.noWait = true
return s return s
@ -37,6 +44,23 @@ func (s *selectLockImpl) SKIP_LOCKED() RowLock {
func (s *selectLockImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) { func (s *selectLockImpl) serialize(statement StatementType, out *SQLBuilder, options ...SerializeOption) {
out.WriteString(s.lockStrength) out.WriteString(s.lockStrength)
if len(s.of) > 0 {
out.WriteString("OF")
for i, of := range s.of {
if i > 0 {
out.WriteString(", ")
}
table := of.Alias()
if table == "" {
table = of.TableName()
}
out.WriteIdentifier(table)
}
}
if s.noWait { if s.noWait {
out.WriteString("NOWAIT") out.WriteString("NOWAIT")
} }

View file

@ -122,6 +122,11 @@ FOR UPDATE;
SELECT table1.col_bool AS "table1.col_bool" SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1 FROM db.table1
FOR SHARE NOWAIT; FOR SHARE NOWAIT;
`)
testutils.AssertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE().OF(table1).NOWAIT()), `
SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1
FOR UPDATE OF table1 NOWAIT;
`) `)
} }

View file

@ -132,5 +132,11 @@ FOR KEY SHARE NOWAIT;
SELECT table1.col_bool AS "table1.col_bool" SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1 FROM db.table1
FOR NO KEY UPDATE SKIP LOCKED; FOR NO KEY UPDATE SKIP LOCKED;
`)
assertStatementSql(t, SELECT(table1ColBool).FROM(table1).FOR(UPDATE().OF(table1, table2).NOWAIT()), `
SELECT table1.col_bool AS "table1.col_bool"
FROM db.table1
FOR UPDATE OF table1, table2 NOWAIT;
`) `)
} }

View file

@ -2251,6 +2251,18 @@ FOR`
} }
} }
func TestRowLockWithJoins(t *testing.T) {
query := SELECT(STAR).
FROM(
Film.
INNER_JOIN(FilmCategory, FilmCategory.FilmID.EQ(Film.FilmID)).
LEFT_JOIN(FilmActor, FilmActor.FilmID.EQ(Film.FilmID))).
LIMIT(1).
FOR(UPDATE().OF(Film, FilmCategory).NOWAIT())
testutils.AssertExecAndRollback(t, query, db, 1)
}
func TestQuickStart(t *testing.T) { func TestQuickStart(t *testing.T) {
var expectedSQL = ` var expectedSQL = `