Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MySQL: Add support for dropping keys #4489

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ alter_table_rules ::= (
| alter_table_modify_column
| alter_table_add_index
| alter_table_drop_index
| alter_table_drop_foreign_key
| alter_table_drop_primary_key
| alter_table_drop_column
| alter_table_convert_character_set
| row_format_clause
Expand Down Expand Up @@ -255,6 +257,11 @@ alter_table_add_constraint ::= ADD table_constraint
alter_table_add_index ::= ADD [ UNIQUE ] [ INDEX | KEY ] [ {index_name} ] LP {indexed_column} ( COMMA {indexed_column} ) * RP

alter_table_drop_index ::= DROP ( INDEX | KEY ) {index_name}
alter_table_drop_foreign_key ::= DROP FOREIGN KEY {column_name} {
mixin = "app.cash.sqldelight.dialects.mysql.grammar.mixins.DropForeignKeyMixin"
pin = 2
}
alter_table_drop_primary_key ::= DROP PRIMARY KEY

placement_clause ::= 'FIRST' | ( AFTER {column_name} )

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package app.cash.sqldelight.dialects.mysql.grammar.mixins

import app.cash.sqldelight.dialects.mysql.grammar.psi.MySqlAlterTableDropForeignKey
import com.alecstrong.sql.psi.core.SqlAnnotationHolder
import com.alecstrong.sql.psi.core.psi.SqlColumnDef
import com.alecstrong.sql.psi.core.psi.SqlColumnName
import com.alecstrong.sql.psi.core.psi.SqlCompositeElementImpl
import com.alecstrong.sql.psi.core.psi.SqlCreateTableStmt
import com.alecstrong.sql.psi.core.psi.SqlTableConstraint
import com.intellij.lang.ASTNode
import com.intellij.psi.util.childrenOfType
import com.intellij.psi.util.parentOfType

internal abstract class DropForeignKeyMixin(
node: ASTNode,
) : SqlCompositeElementImpl(node),
MySqlAlterTableDropForeignKey {
override fun annotate(annotationHolder: SqlAnnotationHolder) {
super.annotate(annotationHolder)
val foreignKey = childrenOfType<SqlColumnName>().single()
val foundColumnDef = foreignKey.getColumnDefOrNull()
if (foundColumnDef == null || !foundColumnDef.isForeignKey()) {
annotationHolder.createErrorAnnotation(
foreignKey,
"${foreignKey.name} is not a foreign key.",
)
}
}

private fun SqlColumnName.getColumnDefOrNull(): SqlColumnDef? {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be moved to sql-psi to allow reusing getting the columnDef and its foreign status in other dialects too, will do it in another PR.

val ref = reference?.resolve() ?: return null
val tables = tablesAvailable(this)
for (table in tables) {
val tableDef = table.tableName.parentOfType<SqlCreateTableStmt>() ?: continue
for (columnDef in tableDef.columnDefList) {
val columnRef = columnDef.columnName.reference
if (columnRef != null && columnRef.resolve() == ref) {
return columnDef
}
}
}
return null
}

private fun SqlColumnDef.isForeignKey(): Boolean {
for (columnConstraint in columnConstraintList) {
if (columnConstraint.foreignKeyClause != null) {
return true
}
}
val createTableStmt: SqlCreateTableStmt? = parentOfType()
if (createTableStmt != null) {
for (tableConstraints in createTableStmt.tableConstraintList) {
val foreignKeyClause = tableConstraints.foreignKeyClause
if (foreignKeyClause != null) {
val columns = (foreignKeyClause.parent as SqlTableConstraint).columnNameList
for (column in columns) {
if (column.reference?.resolve() == columnName) {
return true
}
}
}
}
}
return false
}
}
20 changes: 20 additions & 0 deletions dialects/mysql/src/test/fixtures_mysql/alter-table-drop-key/1.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
CREATE TABLE parent (
id INT NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE child (
id INT,
parent_id INT,
FOREIGN KEY (parent_id) REFERENCES parent(id)
);

ALTER TABLE parent
DROP PRIMARY KEY;

ALTER TABLE child
DROP FOREIGN KEY parent_id;

-- Should fail, id isn't a foreign key
ALTER TABLE child
DROP FOREIGN KEY id;
16 changes: 16 additions & 0 deletions dialects/mysql/src/test/fixtures_mysql/alter-table-drop-key/2.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
CREATE TABLE parent2 (
id INT NOT NULL,
PRIMARY KEY (id)
);

CREATE TABLE child2 (
id INT,
parent_id2 INT REFERENCES parent2(id)
);

ALTER TABLE child2
DROP FOREIGN KEY parent_id2;

-- Should fail, id isn't a foreign key
ALTER TABLE child2
DROP FOREIGN KEY id;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
1.s line 20:19 - id is not a foreign key.
2.s line 16:19 - id is not a foreign key.
Loading