-
Notifications
You must be signed in to change notification settings - Fork 696
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
chore!: Change H2 Oracle longType and longAutoincType from NUMBER(19) to BIGINT and add CHECK constraint in Oracle and SQLite #2273
base: main
Are you sure you want to change the base?
Conversation
de57d51
to
d2cf30f
Compare
val name = column.name | ||
val checkName = "${generatedSignedCheckPrefix}long_$name" | ||
if (checkConstraints.none { it.first == checkName }) { | ||
column.check(checkName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's ok or not, but to me it looks a bit suspicious at the current moment.
We actually modify the table
object, so user will have changes in table object if he tries to create statement for that table.
The method createStatement()
does not look like the one that should modify table object, so some users may be surprised
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@obabichevjb I agree. I didn't like this solution, to be frank, but I didn't have any other ideas. If you have any suggestions on how to do this in a cleaner way, please let me know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a good question, I'm not sure about what is the behavior we want to achieve.
If we want to guarantee that only long values would be stored in the database base and exception would be thrown otherwise, it could be problematic (like in the PR)
I tried to check SQLite, and I found out that if the column type INTEGER
is used, then the column will store only Kotlin's Long values. But it would not complain if the user tried to save the value beyond Long.MIN_VALUE
/Long.MAX_VALUE
, it will just "cut" the values to the range.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've decided to simply exclude SQLite from this expected behaviour simply because the raw SQL does not have that behaviour to begin with, and it is a hassle for Exposed to try to do it. If a user wants to enforce it, they can simply add their own custom check constraint like this:
val long = long("long_column").check { column ->
fun typeOf(value: String) = object : ExpressionWithColumnType<String>() {
override fun toQueryBuilder(queryBuilder: QueryBuilder) = queryBuilder { append("typeof($value)") }
override val columnType: IColumnType<String> = TextColumnType()
}
val typeCondition = Expression.build { typeOf(column.name) eq stringLiteral("integer") }
if (column.columnType.nullable) {
column.isNull() or typeCondition
} else {
typeCondition
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@e5l What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with @obabichevjb about modifying tables in createStatement
, so I'm good if we're not doing that.
The one major thing to consider is a strict mode (like https://dev.mysql.com/doc/refman/8.4/en/sql-mode.html) or strict tables (https://www.sqlite.org/stricttables.html). We should mention these in the docs and check if we're working as expected if those are enabled.
d2cf30f
to
e668a55
Compare
58fba29
to
e9519f5
Compare
… to BIGINT and add CHECK constraint in Oracle and SQLite
e9519f5
to
bc28075
Compare
…iour is that it is not possible to enforce the range without a special CHECK constraint that checks the type
bc28075
to
3f2e4b2
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
left a comment
Description
Detailed description:
The SQL type of H2 Oracle Long type were changed. A CHECK constraint was also added for SQLite and Oracle.
The CHECK constraint with a range doesn't reject out-of-range values in SQLite because SQLite can store values that exceed the 64-bit integer range as REAL (floating-point numbers), bypassing the constraint. Using the condition
typeof(long_column) = 'integer'
instead of the range ensures that only 64-bit integer values pass the check, preventing out-of-range values from being stored as REAL and slipping past the constraint. The reason all of this is done thecreateStatement()
function and not in the column creation function as usual is because we need to invokecurrentDialect
to check the dialect and construct the CHECK constraint accordingly, and this cannot be invoke in the column creation function.Type of Change
Please mark the relevant options with an "X":
Updates/remove existing public API methods:
Affected databases:
Checklist
Related Issues