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

binary type doesn't honor max length #993

Closed
neelkamath opened this issue Jul 11, 2020 · 7 comments
Closed

binary type doesn't honor max length #993

neelkamath opened this issue Jul 11, 2020 · 7 comments

Comments

@neelkamath
Copy link

The binary fixed-length type doesn't seem to honor the provided length: no error is thrown, no warning is logged, and the image isn't even silently trimmed to the specified maximum number of bytes.

Pseudocode for table:

object Images : IntIdTable() {
    private val image: Column<ByteArray> = binary("image", 10)

    fun create(image: ByteArray): Int = transact {
        insertAndGetId { it[this.image] = image }.value
    }

    fun read(id: Int): ByteArray = transact {
        select { Images.id eq id }.first()[image]
    }
}

Pseudocode for test:

class ImagesTest : FunSpec({
    test("size") {
        val id = Images.create("wallpaper.jpg") // A file which is too large, say 400,000 bytes.
        println("Size: ${Images.read(id).size}") // Prints 400,000.
    }
})
@Tapac
Copy link
Contributor

Tapac commented Jul 11, 2020

What Exposed version and database do you use?

@neelkamath
Copy link
Author

Postgres 12.3

Kotlin 1.3.72 + JDK 8 + JVM 13

Gradle 6.5.1 dependencies:

val exposedVersion = "0.26.1"
implementation("org.jetbrains.exposed:exposed-core:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-jdbc:$exposedVersion")
implementation("org.jetbrains.exposed:exposed-java-time:$exposedVersion")

@Tapac
Copy link
Contributor

Tapac commented Jul 12, 2020

There is no client-side validation of length at the moment and PostgreSQL's bytea type doesn't have a limit param. That's why there is no exception.
I will add validation to prevent unexpected value to be written into database.

Tapac added a commit that referenced this issue Jul 12, 2020
Client-side length validation for BinaryColumnType
@Tapac Tapac closed this as completed Jul 12, 2020
@neelkamath
Copy link
Author

Ohh. Thanks.

To me, it looked like the DB would provide validation since the docs don't explicitly state which DBs validate lengths by themselves, and the limitless binary type stated in its KDoc:

**Note:** This function is only supported by Oracle and PostgeSQL dialects, for the rest please specify a length.

Since the limited binary type didn't state anything about DB support in its KDoc, I assumed Postgres had limited binarys. Perhaps I have misunderstood where such documentation should go, but maybe the limited binary type's KDoc should similarly state that Postgres doesn't support it.

@apprme
Copy link

apprme commented Sep 15, 2020

Is it expected that select queries where value in where clause exceeds column length limit throw the exception as well?

As for me throwing exception on insert is better than silently truncating the value. But throwing on select... I am not so sure.

java.lang.IllegalArgumentException: Value 'impersonate:eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJObXBRajJPNmZmZlgyblR2MW5GVFVNIiwicyI6ZmFsc2UsInQiOmZhbHNlLCJpc3MiOiJEZWxpZ2h0ZXggR21iSCIsImV4cCI6MTYwMDA4Mzg2NSwiaWF0IjoxNTk5NDc5MDY1LCJodyI6IjlJUnk5SVZKS2p5aCJ9._0O1bbWxJ8ot7JQnsqoJpqrsg1GZMzUtjNltRAms4Xc' can't be stored to database column because exceeds length (255)
    at org.jetbrains.exposed.sql.VarCharColumnType.notNullValueToDB (ColumnType.kt:541)
    at org.jetbrains.exposed.sql.IColumnType$DefaultImpls.valueToDB (ColumnType.kt:37)
    at org.jetbrains.exposed.sql.ColumnType.valueToDB (ColumnType.kt:71)
    at org.jetbrains.exposed.sql.statements.api.PreparedStatementApi$DefaultImpls.fillParameters (PreparedStatementApi.kt:13)
    at org.jetbrains.exposed.sql.statements.jdbc.JdbcPreparedStatementImpl.fillParameters (JdbcPreparedStatementImpl.kt:9)
    at org.jetbrains.exposed.sql.statements.Statement.executeIn$exposed_core (Statement.kt:53)
    at org.jetbrains.exposed.sql.Transaction.exec (Transaction.kt:129)
    at org.jetbrains.exposed.sql.Query.count (Query.kt:246)

@apprme
Copy link

apprme commented Sep 15, 2020

Interesting that in case of select and VarCharColumnType it does not throw if argument is longer than VarCharColumnType#colLength but shorter than 256, however it throws if it is longer than 255, regardless of VarCharColumnType#colLength

  object T : Table("testlength") {
    val id = varchar("id", 5)
    override val primaryKey = PrimaryKey(id)
  }

  @Test
  fun shouldNotThrowWhenBelow256() {
    transaction {
      val s = "0".repeat(255) // note the column is VARCHAR(5)
      T.select { T.id eq s }.count()
    }
  }

  @Test
  fun shouldNotThrowWhenAbove255() {
    transaction {
      val s = "0".repeat(300)
      T.select { T.id eq s }.count()
    }
  }

MySQL (tested with mysql command line client and server v8.0.19) does not throw a warning and does not truncate the argument before performing the comparison.

mysql> show create table testlen;
+---------+-------------------------------------------------------------------------------------------------------------------------------------+
| Table   | Create Table                                                                                                                        |
+---------+-------------------------------------------------------------------------------------------------------------------------------------+
| testlen | CREATE TABLE `testlen` (
  `id` varchar(5) COLLATE utf8mb4_bin NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin |
+---------+-------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


mysql> insert into testlen values ("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
Query OK, 1 row affected, 1 warning (0.00 sec)

; here warning is expected

mysql> select * from testlen where id = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";
Empty set (0.00 sec)

; no warning here; also 0 results; however exposed throws an exception

@asule90
Copy link

asule90 commented Apr 1, 2021

i still got this issue on postgresql.

Screenshot from 2021-04-01 18-19-05

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants