Conversation
Thirty four deliberately wrong programs, each one asserting the class it raises and the sentence it says, run by both providers. The bar is the one dx/15 section 4 sets: no crash, no leak, and a message that names what the caller did rather than naming a C function. Six of them did not clear that bar, so this fixes those too. A column read as the wrong type said "zu_result_col_i64 answered MISUSE"; it now names the column, what it holds and what the accessor reads. An appender whose connection closed under it said "zu_appender_flush answered MISUSE_CLOSED"; it now says the connection is closed. A result read after it closed handed back a Row that failed later on the first cell instead of refusing at the call. A file that is not a database was an internal error, which asks the caller to report a bug about a path they mistyped, and is now a connection error beside the file that is not there. And the entry points take a null path or a null statement with the parameter named rather than passing it on to a call that will trip over it somewhere else. The second half is lifecycle. Five hundred failed opens, a thousand connections, a thousand failed statements, each with the count of open file descriptors taken either side of them, because a client that leaks a handle per failure passes every single wrong program above and falls over in a server. There is also a test of the programs that look like misuse and are not, so that none of this turns into a client that refuses ordinary work. A MATCH on a label that does not exist is deliberately not in the table. Today it answers no rows rather than saying so, which is an engine matter rather than a client one, and asserting the message we want here would have meant asserting a behaviour that does not exist.
tamnd
added a commit
to tamnd/zu
that referenced
this pull request
Aug 22, 2026
Thirty four deliberately wrong programs in the shared cases module, run by both providers, each asserting the class it raises and the sentence it says. Six of them did not pass when the table was first written, so the same change fixes a column read as the wrong type, an appender whose connection closed under it, a result read after it closed, a file that is not a database being called an internal error, and the entry points that took a null without naming the parameter. The lifecycle half counts open file descriptors either side of five hundred failed opens, a thousand connections and a thousand failed statements. tamnd/zu-java#13. That takes the practice score to 60, and what is left is leaks, install and stability, which are apparatus, and api-map and perf, which are reports the release collects.
22 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is the
misuseitem on the zu-java scorecard, which the clients spec words as: deliberately wrong programs, and for each one no crash, no leak, and a clear message.zudb-tck/src/main/java/dev/zudb/tck/MisuseTest.javais a table of thirty four wrong programs. Each row names what the caller did, the exception class it should raise, and the sentence it should say, and the factory turns each row into its own dynamic test so a failure names the mistake rather than naming a line number in a loop. It lives in the shared cases module, so both the Panama provider and the JNI provider run all of it.Asserting the class alone would have been the easy version and it would have been worthless. A client that answers every mistake with
zu_result_col_i64 answered MISUSEpasses a class assertion. So the text is asserted too, as a substring, chosen to be the part a reader would act on.Six cases did not pass when the table was first written, and this fixes those.
Result.longs,Result.doublesandResult.nodeOffsetsnow check what the column holds before they borrow it. Reading a column of strings as integers used to answerzu_result_col_i64 answered MISUSE, which is a sentence about our implementation. It now says which column it is, what it holds, and what the accessor reads.Appendernow knows the connection it writes through, and refuses with "the connection this appender writes through is closed" rather than passing the call down to an engine that refuses it without an error record attached, which left the caller reading the name of a C function.Result.rownow checks the result is open before it builds aRow. It used to hand back a row that failed on the first cell read, so the exception pointed at the wrong call.Diagnostic.toExceptionmapsCORRUPTtoZuConnectionExceptioninstead of letting it fall through toZuInternalException. A header that says something impossible could be a database this process corrupted and it could be a JPEG somebody pointed at, and the second is what nearly all of them are.ZuInternalExceptiontells a caller to open a bug about somebody else's code. The class doc onZuConnectionExceptionnow says that this reading was chosen and why.Database.open,Database.create,Connection.open,Connection.create,Loader.create,Connection.query,Connection.prepareandConnection.appendername their parameter when it is null, rather than passing it on to a call that trips over it further in.The second half of the file is lifecycle, which no single wrong program catches. Five hundred failed opens, a thousand connections opened and closed, and a thousand failed statements, each with the count of the process's own open file descriptors taken either side. A client that leaks a handle per failure passes every case in the table above and falls over in a server after an afternoon. There is also a test of the programs that look like misuse and are not, closing twice, an appender that finished with nothing in it, a result with no rows read as a borrowed column, a transaction that did nothing and still rolls back, so that none of this turns into a client that refuses ordinary work.
DiagnosticTestmoved with the mapping change, and gained theUNKNOWNcase that is now the one landing inZuInternalException.Checked on a Linux box against a release build of the engine.
MisuseTestis 41 tests green on both providers, and the full reactor is green: API, TCK, Panama, JNI, Arrow and benchmarks, in 2m45s. The suite was also checked to bite, by taking the type check back out ofResult.longsand watching the case go red withzu_result_col_i64 answered MISUSEprinted against the sentence it was supposed to say.One case is deliberately not in the table. A MATCH on a label that does not exist answers no rows today rather than saying the label is unknown. That is an engine matter and not a client one, and putting it in would have meant asserting a message that nothing produces. The appender is the call that does refuse an unknown table, so that is the case the table carries.