|
5 | 5 |
|
6 | 6 | == Status |
7 | 7 |
|
8 | | -* Draft |
9 | | -* Proposed for: Jaybird 7 |
| 8 | +* Published: 2025-11-13 |
| 9 | +* Implemented in: Jaybird 7 |
10 | 10 |
|
11 | 11 | == Type |
12 | 12 |
|
|
35 | 35 | ==== 8.3.1 Silent Truncation |
36 | 36 |
|
37 | 37 | The `Statement.setMaxFieldSize` method allows a maximum size (in bytes) to be set. |
38 | | -This limit applies only to the `BINARY`, `VARBINARY`, `LONGVARBINARY`, `CHAR`, `VARCHAR`, `LONGVARCHAR`, `NCHAR`, `NVARCHAR`, and `LONGNVARCHAR` data types. |
| 38 | +This limit applies only to the (JDBC types) `BINARY`, `VARBINARY`, `LONGVARBINARY`, `CHAR`, `VARCHAR`, `LONGVARCHAR`, `NCHAR`, `NVARCHAR`, and `LONGNVARCHAR` data types. |
39 | 39 | If a limit has been set using `setMaxFieldSize` and there is an attempt to read data that exceeds the limit, any truncation that occurs as a result of exceeding the set limit will _not_ be reported. |
40 | 40 | ____ |
41 | 41 |
|
42 | | -Firebird doesn't provide a way to restrict the maximum number of bytes returned that will not result in string truncation errors for longer values, or -- for shorter values -- would result in _"`wrong`"_ client-side length derivations of variable length encodings like UTF8 (which would result in excessive truncation). |
| 42 | +Firebird doesn't provide a way to restrict the maximum number of bytes returned that will not result in string truncation errors for longer values, or -- for shorter values -- would result in "`wrong`" client-side length derivations of variable length encodings like UTF8 (which would result in excessive truncation). |
43 | 43 |
|
44 | | -Jaybird considers `BLOB SUB_TYPE TEXT` to be `LONGVARCHAR` and `BLOB SUB_TYPE BINARY` to be `LONGVARBINARY` (though all blob subtypes can be treated that way). |
| 44 | +Jaybird considers `BLOB SUB_TYPE TEXT` to be `LONGVARCHAR` and `BLOB SUB_TYPE BINARY` and other Firebird subtypes to be `LONGVARBINARY`. |
| 45 | +Custom subtypes (negative subtypes), are considered `Types.BLOB` |
45 | 46 |
|
46 | 47 | == Decision |
47 | 48 |
|
48 | 49 | Jaybird 7 implements support for `setMaxFieldSize`/`getMaxFieldSize` using client-side truncation. |
49 | | -This will be implemented for `CHAR`, `VARCHAR`, `BINARY`, and `VARBINARY`. |
| 50 | +This will be implemented for `CHAR`, `VARCHAR`, `BINARY`, `VARBINARY`, `LONGVARCHAR` and `LONGVARBINARY` |
50 | 51 |
|
51 | 52 | To avoid problems with `RDB$DB_KEY` columns, implementation must ignore the limit for those columns, as indicated by `FieldDescriptor.isDbKey()`. |
52 | 53 |
|
53 | | -Decision for handling `LONGVARCHAR`/`LONGVARBINARY` is pending further investigation. |
54 | | -Currently, we're leaning towards _not_ honouring the maximum field size, or only for `ResultSet.getBytes`/`getString`. |
| 54 | +Custom blob types (i.e. with a negative subtype) are not affected, as Jaybird considers those `Types.BLOB`. |
55 | 55 |
|
56 | 56 | == Consequences |
57 | 57 |
|
58 | | -Handling the truncation for `CHAR`, `VARCHAR`, `BINARY`, and `VARBINARY` will be delegated to the `FbStatement` implementation. |
59 | | -The truncation will be done when receiving the data from the server (from the wire, or from fbclient). |
60 | | - |
61 | | -`FbStatement` will receive an `int` property `maxFieldSize` (getter/setter pair) with a default implementation that ignores the set value and returns 0. |
62 | | -The actual implementation will override this, and use the set value when receiving data from the server. |
63 | | - |
64 | | -Caveats or possible pitfalls: |
65 | | - |
66 | | -* Given the truncation happens at a set number of bytes, values in a multibyte character set (UTF8) might end in the Unicode replacement character due to truncation before the end of the encoded codepoint. |
67 | | -* The detection of `RDB$DB_KEY` column will also ignore "`normal`" `BINARY` columns called `DB_KEY`. |
| 58 | +For `CHAR`, `VARCHAR`, `BINARY`, and `VARBINARY`, truncation is implemented in the `FbStatement` implementations in the GDS-ng layer. |
| 59 | +The truncation is done when fetching the data from the server (wire protocol), or from fbclient (native/embedded). |
| 60 | + |
| 61 | +`FbStatement` has an `int` property `maxFieldSize` with a default implementation that ignores the set value and returns `0`. |
| 62 | +The actual implementations override this, and use the set value when receiving data from the server or native client. |
| 63 | + |
| 64 | +For `LONGVARCHAR`/`LONGVARBINARY`, this is implemented in the relevant `FBField` implementations and configured from `FBResultSet`. |
| 65 | + |
| 66 | +* For non-cached blobs, the maximum length is applied for `getBytes` and getters relying on `getBytes`, like the getters for string, numeric, Boolean and datetime types, and `getObject` that returns any of those types, but not to getters returning `Blob`, `Clob`, `InputStream`, or `Reader`. |
| 67 | ++ |
| 68 | +In case of `InputStream` and `Reader`, such behaviour doesn't conform to the JDBC requirements, but this avoids complications in the implementation. |
| 69 | +We may address this in the future (e.g. maybe if we implement support for `Blob.getBinaryStream(long, long)`). |
| 70 | ++ |
| 71 | +Supporting `Blob` and `Clob` for `LONGVARCHAR` and `LONGVARBINARY` is already a non-standard extension so -- in our opinion -- not subject to these requirements. |
| 72 | +* For cached blobs (as used in holdable or emulated scrollable result sets), the maximum length is also applied to methods returning `Blob`, `Clob`, `InputStream`, or `Reader`. |
| 73 | + |
| 74 | +Caveats: |
| 75 | + |
| 76 | +* Given the truncation happens at a set number of bytes, values in a multibyte character set (UTF8) might end in the Unicode replacement character (U+FFFD, '`�`') due to truncation before the end of the encoded codepoint. |
| 77 | +* Jaybird will accept any non-negative value for `maxFieldSize`. |
| 78 | +The JDBC apidoc recommends using values greater than `256`. |
| 79 | +* A too small `maxFieldSize` may result in "`wrong`" values being returned without error for numeric and Boolean getters; |
| 80 | +for datetime getters it may result in missing precision without errors, or parse errors. |
| 81 | +* Setting the max field size after execute may not be immediately applied to the current result set for `CHAR`, `VARCHAR`, `BINARY`, and `VARBINARY`: |
| 82 | +** For a locally cached result set: never, as the rows were truncated to the `maxFieldSize` on execute. |
| 83 | +** Otherwise, already fetched rows are truncated to the `maxFieldSize` on their fetch, and only rows returned by a subsequent fetch will apply the new limit. |
| 84 | +* For `LONGVARCHAR`/`LONGVARBINARY`, the value will be truncated on access, with the following caveats: |
| 85 | +** For cached blobs, the limit is applied on retrieval, and applies to all methods (as the cached value is truncated). |
| 86 | +** The value of a cached blob (holdable result set or emulated scrollable result set) will be truncated to the initial `maxFieldSize`. |
| 87 | +Subsequent use of a larger `maxFieldSize` will continue to return the shorter value. |
| 88 | +* The detection of `RDB$DB_KEY` columns includes "`normal`" `BINARY`/`CHAR CHARACTER SET OCTETS` columns called `DB_KEY`. |
68 | 89 |
|
69 | 90 | [appendix] |
70 | 91 | == License Notice |
|
0 commit comments