makssent opened a new pull request, #40211:
URL: https://github.com/apache/shardingsphere/pull/40211

   Changes proposed in this pull request:
     - `CHARACTER SET OCTETS` means a binary string: the value is stored as 
bytes without an encoding. Jaybird reads `CHARACTER SET OCTETS` values as 
`byte[]` and maps a `VARCHAR(n) CHARACTER SET OCTETS` column to the JDBC type 
`VARBINARY` and a `CHAR(n) CHARACTER SET OCTETS` column to the JDBC type 
`BINARY`.
     - `FirebirdPrepareStatementCommandExecutor` describes the columns and 
parameters in the response to `op_prepare`. For a `VARCHAR(n) CHARACTER SET 
OCTETS` column (the JDBC type `VARBINARY` in the ShardingSphere metadata), 
`FirebirdPrepareStatementCommandExecutor` now takes the column length from 
`FirebirdNonFixedLengthColumnSizeRegistry`, as for `CHAR` and `VARCHAR` columns.
       - `FirebirdNonFixedLengthColumnSizeRegistry` keeps the lengths of text 
columns that the Firebird module reads from the system tables when the metadata 
is loaded: the common ShardingSphere metadata (`ShardingSphereColumn`) has no 
column length.
     - For a `VARCHAR(n) CHARACTER SET OCTETS` column, 
`FirebirdReturnColumnPacket` now writes the sub type 1 (`OCTETS`).
       - The sub type (`sqlsubtype`) of a text column in the description holds 
the character set id, and id 1 means `OCTETS`. The length and sub type of a 
text column are produced by 
[Firebird](https://github.com/FirebirdSQL/firebird/blob/v5.0.4/src/common/dsc.cpp#L1716-L1720),
 and 
[Jaybird](https://github.com/FirebirdSQL/jaybird/blob/v6.0.6/src/main/org/firebirdsql/jdbc/field/JdbcTypeConverter.java#L113-L114)
 maps a column with sub type 1 to `VARBINARY` and reads the column value as 
`byte[]`.
     - `FirebirdBlrRowMetadata` parses the BLR with which the client describes 
the parameter values in `op_execute`; now `FirebirdBlrRowMetadata` also keeps 
the character set of `blr_varying2` and `blr_text2` fields. 
`FirebirdExecuteStatementPacket` reads the value of a `VARCHAR` parameter in 
the `OCTETS` character set as bytes, not as a string in the connection encoding.
       - The character set of `blr_varying2` and `blr_text2` fields is written 
by 
[Jaybird](https://github.com/FirebirdSQL/jaybird/blob/v6.0.6/src/main/org/firebirdsql/gds/ng/wire/DefaultBlrCalculator.java#L183-L198)
 and read by 
[Firebird](https://github.com/FirebirdSQL/firebird/blob/v5.0.4/src/remote/parser.cpp#L203-L223).
       - Without this change, `FirebirdExecuteStatementPacket` would decode the 
bytes of the value as a string in the connection encoding, and bytes that are 
not valid UTF-8 (for example, `0xff`) would be stored in the table corrupted.
     - Previously, the proxy could not prepare a statement with a `VARCHAR(n) 
CHARACTER SET OCTETS` parameter or select column. For example, the proxy 
answered the prepare of `INSERT INTO T_PD (ID, VO) VALUES (?, ?)` with the 
error `isc_random` ("Unknown exception… "this.columnLength" is null"), because 
the proxy had no length of the column `VO`. Now the proxy describes `VARCHAR(n) 
CHARACTER SET OCTETS` parameters and columns as the Firebird server does 
(`SQL_VARYING`, sub type 1, length 10) and stores in the table the bytes sent 
by the client.
   
   ---
   
     - `FirebirdBinaryColumnType` chooses the Firebird type of a column 
description by the JDBC type of the column in the metadata. For `CHAR(n) 
CHARACTER SET OCTETS` (the JDBC type `BINARY`), `FirebirdBinaryColumnType` now 
chooses `VARYING` instead of `TEXT`: the proxy describes all `CHAR` columns as 
`VARCHAR`, and a `CHAR(n) CHARACTER SET OCTETS` column is now described in the 
same way as the `VARCHAR(n) CHARACTER SET OCTETS` column in the first part.
     - `FirebirdPrepareStatementCommandExecutor` takes the length of a `CHAR(n) 
CHARACTER SET OCTETS` column from `FirebirdNonFixedLengthColumnSizeRegistry`, 
and `FirebirdReturnColumnPacket` writes the sub type 1 (`OCTETS`) for a 
`CHAR(n) CHARACTER SET OCTETS` column, as for the `VARCHAR(n) CHARACTER SET 
OCTETS` column in the first part.
       - The length and sub type of a `CHAR` column are produced by 
[Firebird](https://github.com/FirebirdSQL/firebird/blob/v5.0.4/src/common/dsc.cpp#L1705-L1708),
 and 
[Jaybird](https://github.com/FirebirdSQL/jaybird/blob/v6.0.6/src/main/org/firebirdsql/jdbc/field/JdbcTypeConverter.java#L113-L114)
 maps a column with sub type 1 to a binary type and reads the column value as 
`byte[]`.
       - The client sends the value of a `CHAR(n) CHARACTER SET OCTETS` 
parameter in a `blr_varying2` field with the `OCTETS` character set, because 
the proxy describes the parameter as `VARCHAR` with sub type 1; 
`FirebirdExecuteStatementPacket` from the first part reads the value of a 
`CHAR(n) CHARACTER SET OCTETS` parameter as bytes.
     - Previously, the proxy could not prepare a statement with a `CHAR(n) 
CHARACTER SET OCTETS` parameter or select column. For example, the proxy 
answered the prepare of `INSERT INTO T_CO (ID, CO) VALUES (?, ?)` with the same 
error `isc_random`, because the proxy had no length of the column `CO`. Now the 
proxy describes `CHAR(n) CHARACTER SET OCTETS` parameters and columns with the 
same length and sub type as the Firebird server (length 4, sub type 1) and 
passes the values as bytes. The proxy describes the column type as `VARCHAR`, 
and the server as `CHAR`: the proxy describes all `CHAR` columns in this way, 
and this pull request does not change that rule.
   
   <details>
   <summary>Verification</summary>
   
   The same queries were executed directly against a real database and through 
the proxy, and the results were compared.
   
   * Server: Firebird 5.0
   * Clients: Jaybird 5.0.13 and 6.0.6
   
     Tables `T_PD (ID INTEGER NOT NULL PRIMARY KEY, VO VARCHAR(10) CHARACTER 
SET OCTETS)` and `T_CO (ID INTEGER NOT NULL PRIMARY KEY, CO CHAR(4) CHARACTER 
SET OCTETS)`, connection encoding UTF8; some values are not valid UTF-8. Both 
`SELECT` from `T_PD` also have `ID BETWEEN 4401 AND 4404 ORDER BY ID`, and 
`SELECT ... WHERE CO = ?` also has `ID BETWEEN 5101 AND 5103`. The cells show 
the precision of parameters and columns (`getPrecision`), the result rows and 
the number of changed rows; the values of `VO` and `CO` are read as `byte[]` 
and shown in hex. Type names are not compared: the proxy describes every `CHAR` 
column as `VARCHAR`, and the server describes `CO` as `CHAR`. Jaybird 5 and 6 
give the same results. "Before the fix" is the proxy from `master`.
   
     Before the fix:
   
     | Query | Proxy | Server | Match |
     |---|---|---|---|
     | `INSERT INTO T_PD (ID, VO) VALUES (?, ?)` | prepare error `isc_random` 
`Unknown exception. More details: java.lang.NullPointerException: Cannot invoke 
"java.lang.Integer.intValue()" because "this.columnLength" is null` | 
parameters 10, 10 | no |
     | The same `INSERT` of rows 4401 `0x0102ff`, 4402 empty array, 4403 NULL, 
4404 `0x007f8041424344454647` | not executed | each changed 1 | no |
     | `UPDATE T_PD SET VO = ? WHERE ID = ?`, `0xc328`, 4402 | the same error | 
parameters 10, 10; changed 1 | no |
     | `SELECT ID, VO FROM T_PD WHERE VO = ?`, `0x0102ff` | the same error | 
parameters 10; columns 10, 10; rows (4401, 0x0102ff) | no |
     | `SELECT ID, VO FROM T_PD` | the same error | columns 10, 10; rows (4401, 
0x0102ff), (4402, 0xc328), (4403, NULL), (4404, 0x007f8041424344454647) | no |
     | Rows of `T_PD` read directly from the server, and `DELETE FROM T_PD 
WHERE ID BETWEEN 4401 AND 4404` | no rows; changed 0 | the same 4 rows; changed 
4 | no |
     | `INSERT INTO T_CO (ID, CO) VALUES (5101, X'0102FF00')` | changed 1 | 
changed 1 | yes |
     | `INSERT INTO T_CO (ID, CO) VALUES (?, ?)`, 5102 and `0xab000102`, then 
5103 and `0x0707` | prepare error `isc_random` `Unknown exception. More 
details: java.lang.NullPointerException: Cannot invoke 
"java.lang.Integer.intValue()" because "this.columnLength" is null` | 
parameters 10, 4; each changed 1 | no |
     | `SELECT ID FROM T_CO WHERE CO = ?`, `0x0102ff00` | the same error | 
parameters 4; rows (5101) | no |
     | `UPDATE T_CO SET CO = ? WHERE ID = 5103`, `0x09090909` | the same error 
| parameters 4; changed 1 | no |
     | `SELECT ID, CO FROM T_CO` | the same error | columns 10, 4; rows (5101, 
0x0102ff00), (5102, 0xab000102), (5103, 0x09090909) | no |
     | `DELETE FROM T_CO WHERE ID BETWEEN 5101 AND 5103` | changed 1 | changed 
3 | no |
   
     After the fix:
   
     | Query | Proxy | Server | Match |
     |---|---|---|---|
     | `INSERT INTO T_PD (ID, VO) VALUES (?, ?)` of rows 4401, 4402, 4403 and 
4404 | parameters 10, 10; each changed 1 | parameters 10, 10; each changed 1 | 
yes |
     | `UPDATE T_PD SET VO = ? WHERE ID = ?`, `0xc328`, 4402 | parameters 10, 
10; changed 1 | parameters 10, 10; changed 1 | yes |
     | `SELECT ID, VO FROM T_PD WHERE VO = ?`, `0x0102ff` | parameters 10; 
columns 10, 10; rows (4401, 0x0102ff) | parameters 10; columns 10, 10; rows 
(4401, 0x0102ff) | yes |
     | `SELECT ID, VO FROM T_PD` | columns 10, 10; rows (4401, 0x0102ff), 
(4402, 0xc328), (4403, NULL), (4404, 0x007f8041424344454647) | columns 10, 10; 
rows (4401, 0x0102ff), (4402, 0xc328), (4403, NULL), (4404, 
0x007f8041424344454647) | yes |
     | Rows of `T_PD` read directly from the server, and `DELETE FROM T_PD 
WHERE ID BETWEEN 4401 AND 4404` | the same 4 rows; changed 4 | the same 4 rows; 
changed 4 | yes |
     | `INSERT INTO T_CO (ID, CO) VALUES (5101, X'0102FF00')` | changed 1 | 
changed 1 | yes |
     | `INSERT INTO T_CO (ID, CO) VALUES (?, ?)`, 5102 and `0xab000102`, then 
5103 and `0x0707` | parameters 10, 4; each changed 1 | parameters 10, 4; each 
changed 1 | yes |
     | `SELECT ID FROM T_CO WHERE CO = ?`, `0x0102ff00` | parameters 4; rows 
(5101) | parameters 4; rows (5101) | yes |
     | `UPDATE T_CO SET CO = ? WHERE ID = 5103`, `0x09090909` | parameters 4; 
changed 1 | parameters 4; changed 1 | yes |
     | `SELECT ID, CO FROM T_CO` | columns 10, 4; rows (5101, 0x0102ff00), 
(5102, 0xab000102), (5103, 0x09090909) | columns 10, 4; rows (5101, 
0x0102ff00), (5102, 0xab000102), (5103, 0x09090909) | yes |
     | `DELETE FROM T_CO WHERE ID BETWEEN 5101 AND 5103` | changed 3 | changed 
3 | yes |
   
   </details>
   
   ---
   
   Before committing this PR, I'm sure that I have checked the following 
options:
   - [x] My code follows the [code of 
conduct](https://shardingsphere.apache.org/community/en/involved/conduct/code/) 
of this project.
   - [x] I have self-reviewed the commit code.
   - [ ] I have (or in comment I request) added corresponding labels for the 
pull request.
   - [ ] I have passed maven check locally : `./mvnw clean install -B -T1C 
-Dmaven.javadoc.skip -Dmaven.jacoco.skip -e`.
   - [ ] I have made corresponding changes to the documentation.
   - [x] I have added corresponding unit tests for my changes.
   - [ ] I have updated the Release Notes of the current development version. 
For more details, see [Update Release 
Note](https://shardingsphere.apache.org/community/en/involved/contribute/contributor/)
   - [ ] I have specified the tool and the affected files or area for 
substantial AI assistance, as required by the [AI-assisted contribution policy].
   
   [AI-assisted contribution policy]: 
https://github.com/apache/shardingsphere/blob/master/AI_POLICY.md


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to