feat(parser): extend Parser with parseTablePrimaryKey
This commit is contained in:
1 parent
48fa9202a4
commit
4e101e46eb
1 file changed
+61
-9
@@ -420,18 +420,58 @@ class Parser(private val tokens: List<Token>) {
|
|||||||
return CreateTableStatement(tableName, columns, foreignKeys, checks, uniqueConstraints, compositePrimaryKey, temporary)
|
return CreateTableStatement(tableName, columns, foreignKeys, checks, uniqueConstraints, compositePrimaryKey, temporary)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseColumnDefinition(): Column {
|
private fun parseTablePrimaryKey(): List<String> {
|
||||||
val columnName = expectIdentifier("expected column name")
|
expect(TokenType.Primary, "expected PRIMARY")
|
||||||
val typeToken = advance()
|
expect(TokenType.Key, "expected KEY after PRIMARY")
|
||||||
val type = when (typeToken.type) {
|
expect(TokenType.LeftParen, "expected '(' after PRIMARY KEY")
|
||||||
TokenType.Integer -> ColumnType.Integer
|
val columns = mutableListOf<String>()
|
||||||
TokenType.Text -> ColumnType.Text
|
do {
|
||||||
TokenType.Boolean -> ColumnType.Boolean
|
columns.add(expectIdentifier("expected column name"))
|
||||||
TokenType.Real -> ColumnType.Real
|
} while (match(TokenType.Comma))
|
||||||
else -> throw error("expected a column type but found '${describe(typeToken)}'", typeToken)
|
expect(TokenType.RightParen, "expected ')' after PRIMARY KEY column list")
|
||||||
|
return columns
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `CONSTRAINT name FOREIGN KEY (...) | CHECK (...) | UNIQUE (...)` - a named table-level
|
||||||
|
* constraint, standard SQL syntax this engine accepts both inline in `CREATE TABLE` (here) and
|
||||||
|
* via `ALTER TABLE ... ADD` (see [parseAlterTable]'s identical dispatch). `PRIMARY KEY` is
|
||||||
|
* deliberately not accepted after `CONSTRAINT name`: [kestrel.catalog.TableSchema] has no name
|
||||||
|
* field for a table's PRIMARY KEY at all, so there would be nowhere to put it, and
|
||||||
|
* `ALTER TABLE ... DROP CONSTRAINT` never needs to target a PRIMARY KEY (see
|
||||||
|
* [kestrel.catalog.Catalog.dropColumn]'s own doc on why dropping a PRIMARY KEY is out of scope
|
||||||
|
* entirely - redesign it or drop the table instead).
|
||||||
|
*/
|
||||||
|
private fun parseNamedTableConstraint(
|
||||||
|
foreignKeys: MutableList<ForeignKeyConstraint>,
|
||||||
|
checks: MutableList<CheckConstraint>,
|
||||||
|
uniqueConstraints: MutableList<UniqueConstraint>
|
||||||
|
) {
|
||||||
|
advance()
|
||||||
|
val name = expectIdentifier("expected constraint name after CONSTRAINT")
|
||||||
|
when {
|
||||||
|
check(TokenType.Foreign) -> foreignKeys.add(parseTableForeignKey().copy(name = name))
|
||||||
|
check(TokenType.Check) -> checks.add(parseTableCheck().copy(name = name))
|
||||||
|
check(TokenType.Unique) -> uniqueConstraints.add(parseTableUnique().copy(name = name))
|
||||||
|
else -> throw error(
|
||||||
|
"expected FOREIGN KEY, CHECK, or UNIQUE after CONSTRAINT $name but found '${describe(peek())}'",
|
||||||
|
peek()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseColumnDefinition(
|
||||||
|
foreignKeys: MutableList<ForeignKeyConstraint>,
|
||||||
|
checks: MutableList<CheckConstraint>,
|
||||||
|
uniqueConstraints: MutableList<UniqueConstraint>
|
||||||
|
): Column {
|
||||||
|
val columnName = expectIdentifier("expected column name")
|
||||||
|
val spec = parseTypeSpec()
|
||||||
var notNull = false
|
var notNull = false
|
||||||
var primaryKey = false
|
var primaryKey = false
|
||||||
|
var default: Expression? = null
|
||||||
|
var generated: Expression? = null
|
||||||
|
var collation = Collation.Binary
|
||||||
while (true) {
|
while (true) {
|
||||||
when {
|
when {
|
||||||
check(TokenType.Not) -> {
|
check(TokenType.Not) -> {
|
||||||
@@ -445,6 +485,18 @@ class Parser(private val tokens: List<Token>) {
|
|||||||
primaryKey = true
|
primaryKey = true
|
||||||
notNull = true
|
notNull = true
|
||||||
}
|
}
|
||||||
|
check(TokenType.Unique) -> {
|
||||||
|
advance()
|
||||||
|
uniqueConstraints.add(UniqueConstraint(null, listOf(columnName)))
|
||||||
|
}
|
||||||
|
check(TokenType.References) -> foreignKeys.add(parseInlineForeignKey(columnName))
|
||||||
|
check(TokenType.Check) -> checks.add(parseColumnCheck())
|
||||||
|
check(TokenType.Default) -> {
|
||||||
|
advance()
|
||||||
|
default = parseExpression()
|
||||||
|
}
|
||||||
|
isContextualKeyword("GENERATED") -> generated = parseGeneratedClause()
|
||||||
|
check(TokenType.Collate) -> collation = parseColumnCollation()
|
||||||
else -> break
|
else -> break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user