apache/shardingsphere · error · SQLFeatureNotSupportedException
execute with SQL for PreparedStatement
Error message
execute with SQL for PreparedStatement
What it means
ShardingSphere's PreparedStatement does not support execute(String sql) — the boolean-returning execute that accepts a new SQL string. Because the routed and rewritten SQL is fixed when prepareStatement(sql) is called, executing a different statement through the same object would defeat sharding. All String overloads of execute are final and throw SQLFeatureNotSupportedException.
Source
Thrown at jdbc/src/main/java/org/apache/shardingsphere/driver/jdbc/unsupported/AbstractUnsupportedOperationPreparedStatement.java:114
@Override
public final int executeUpdate(final String sql, final int autoGeneratedKeys) throws SQLException {
throw new SQLFeatureNotSupportedException("executeUpdate with SQL for PreparedStatement");
}
@Override
public final int executeUpdate(final String sql, final int[] columnIndexes) throws SQLException {
throw new SQLFeatureNotSupportedException("executeUpdate with SQL for PreparedStatement");
}
@Override
public final int executeUpdate(final String sql, final String[] columnNames) throws SQLException {
throw new SQLFeatureNotSupportedException("executeUpdate with SQL for PreparedStatement");
}
@Override
public final boolean execute(final String sql) throws SQLException {
throw new SQLFeatureNotSupportedException("execute with SQL for PreparedStatement");
}
@Override
public final boolean execute(final String sql, final int autoGeneratedKeys) throws SQLException {
throw new SQLFeatureNotSupportedException("execute with SQL for PreparedStatement");
}
@Override
public final boolean execute(final String sql, final int[] columnIndexes) throws SQLException {
throw new SQLFeatureNotSupportedException("execute with SQL for PreparedStatement");
}
@Override
public final boolean execute(final String sql, final String[] columnNames) throws SQLException {
throw new SQLFeatureNotSupportedException("execute with SQL for PreparedStatement");
}
}
View on GitHub (pinned to e952770a21)
Solutions
- Call the parameterless ps.execute() and keep the SQL only in prepareStatement(sql).
- If the code needs to know whether a ResultSet came back, use the boolean return of execute() and then getResultSet()/getUpdateCount().
- Use ps.executeQuery() or ps.executeUpdate() directly when the statement kind is known.
- For truly dynamic SQL strings per call, use Statement.execute(sql) instead.
Example fix
// before PreparedStatement ps = conn.prepareStatement(sql); boolean isRs = ps.execute(sql); // throws // after PreparedStatement ps = conn.prepareStatement(sql); ps.setInt(1, 42); boolean isRs = ps.execute();
Defensive patterns
Strategy: try-catch
Validate before calling
if (stmt instanceof PreparedStatement && sqlArgument != null) {
throw new IllegalArgumentException("execute(String) unsupported on PreparedStatement (ShardingSphere)");
} Try / catch
try {
boolean isRs = ps.execute(sql);
} catch (SQLFeatureNotSupportedException e) {
boolean isRs = ps.execute();
} Prevention
- Write separate code paths for Statement and PreparedStatement instead of sharing execute(sql).
- Use query()/update() style helper methods that hide the execute-family choice.
- Add a unit test asserting your DAO never calls String overloads on prepared statements.
When it happens
Trigger: Calling ps.execute("SELECT ...") or ps.execute("INSERT ...") — any boolean execute(String ...) — on a PreparedStatement from ShardingSphereDataSource. Works on vanilla drivers, throws here.
Common situations: Generic DAO layers that decide between query and update at runtime by calling execute(sql) regardless of statement type; dynamic-SQL frameworks; code migrated from Statement where execute(String) was the norm.
Related errors
AI-assisted analysis of apache/shardingsphere@e952770a21 (2026-08-14).
Data as JSON: /api/errors/fea62fa043ea0dd5.
Report an issue: GitHub.