{"record":{"id":"766519210498f06a","repo":"tursodatabase/turso","slug":"exception-while-binding-long-value-at-position","errorCode":null,"errorMessage":"Exception while binding long value at position \" + position","messagePattern":"Exception while binding long value at position \" \\+ position","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"error","filePath":"bindings/java/src/main/java/tech/turso/core/TursoStatement.java","lineNumber":154,"sourceCode":"   * @return A result code indicating the success or failure of the operation.\n   * @throws SQLException If a database access error occurs.\n   */\n  public int bindInt(int position, int value) throws SQLException {\n    return bindLong(position, value);\n  }\n\n  /**\n   * Binds a long value to the prepared statement at the specified position.\n   *\n   * @param position The index of the SQL parameter to be set.\n   * @param value The value to bind to the parameter.\n   * @return <a href=\"https://www.sqlite.org/c3ref/c_abort.html\">Result Codes</a>\n   * @throws SQLException If a database access error occurs.\n   */\n  public int bindLong(int position, long value) throws SQLException {\n    final int result = bindLong(statementPointer, position, value);\n    if (result != 0) {\n      throw new SQLException(\"Exception while binding long value at position \" + position);\n    }\n    return result;\n  }\n\n  private native int bindLong(long statementPointer, int position, long value) throws SQLException;\n\n  /**\n   * Binds a double value to the prepared statement at the specified position.\n   *\n   * @param position The index of the SQL parameter to be set.\n   * @param value The value to bind to the parameter.\n   * @return <a href=\"https://www.sqlite.org/c3ref/c_abort.html\">Result Codes</a>\n   * @throws SQLException If a database access error occurs.\n   */\n  public int bindDouble(int position, double value) throws SQLException {\n    final int result = bindDouble(statementPointer, position, value);\n    if (result != 0) {\n      throw new SQLException(\"Exception while binding double value at position \" + position);","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/tursodatabase/turso/blob/bad083fafbefdeae9a42ec19bdaaad8918dcf411/bindings/java/src/main/java/tech/turso/core/TursoStatement.java#L136-L172","documentation":"Thrown when the JNI-native bindLong call on a prepared statement returns a non-zero SQLite result code instead of SQLITE_OK. The native layer (bindings/java/rs_src/turso_statement.rs) returns SQLITE_ERROR in two cases: the statement pointer no longer resolves to a live statement (closed/finalized or stale handle), or bind_at rejects the parameter position as out of range. Note that parameter positions are 1-based; position 0 actually panics inside the native NonZero::new().unwrap().","triggerScenarios":"Calling stmt.bindLong(position, value) with position greater than stmt.parameterCount(); passing a 0-based index (e.g. 0 for the first parameter); calling bindLong on a statement after close() or after its connection was closed; concurrently finalizing the statement while another thread binds.","commonSituations":"Loops that bind an argument array with 0-based indices; SQL whose placeholder count does not match the number of bind calls after editing the query; reusing a cached PreparedStatement after the pool recycled it; sharing a statement across threads without synchronization.","solutions":["Use 1-based positions: bind parameter i at index i + 1.","Check 1 <= position <= stmt.parameterCount() before every bind and fail fast with a clear message if the argument count mismatches the SQL.","Verify !stmt.isClosed() (and that the connection is open) before binding; do not bind on statements returned to a pool.","Keep statement usage confined to one thread or synchronize access, since the native pointer is released on close."],"exampleFix":"// before\nfor (int i = 0; i < args.length; i++) {\n    stmt.bindLong(i, ((Number) args[i]).longValue()); // 0-based index: position 0 panics, off-by-one binds\n}\n\n// after\nint paramCount = stmt.parameterCount();\nif (args.length != paramCount) {\n    throw new IllegalArgumentException(\"SQL expects \" + paramCount + \" params, got \" + args.length);\n}\nfor (int i = 0; i < args.length; i++) {\n    stmt.bindLong(i + 1, ((Number) args[i]).longValue()); // 1-based positions\n}","handlingStrategy":"validation","validationCode":"if (stmt.isClosed()) {\n    throw new IllegalStateException(\"cannot bind on closed statement\");\n}\nint count = stmt.parameterCount();\nif (position < 1 || position > count) {\n    throw new IllegalArgumentException(\n        \"bind position \" + position + \" out of range 1..\" + count + \" for SQL: \" + sql);\n}\nstmt.bindLong(position, value);","typeGuard":null,"tryCatchPattern":"try {\n    stmt.bindLong(position, value);\n} catch (SQLException e) {\n    throw new IllegalStateException(\n        \"bindLong failed at position \" + position + \" for SQL: \" + sql\n        + \" (expected params=\" + expectedParamCount + \")\", e);\n}","preventionTips":["Treat parameter positions as 1-based everywhere; never feed a 0-based loop index directly.","Assert args.length == stmt.parameterCount() once before any bind loop.","Build SQL text and its parameter list in the same method so they cannot diverge.","Never bind on a statement that another thread or an error path may have closed."],"tags":["java","jdbc","binding","long","jni","parameter-position"],"backgroundTag":"jdbc-parameter-binding","analyzedSha":"bad083fafbefdeae9a42ec19bdaaad8918dcf411","analyzedAt":"2026-08-16T23:12:11.798Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}