Closed markddrake closed 2 years ago
I was eventually able to avoid passing data as to HEX and the converting back on the server by binding all BUFFERS as BLOB, regardless of what the actual column data types is, however I cannot get it to work if I bind BUFFERS as VARBINAY
@markddrake Currently in ibm_db code, support for VARBINARY is missing. Instead you can use BINARY. Thanks.
Stilll cannot get this working without using HEXTORAW and RAWTOHEX..
See following example
import ibmdb from 'ibm_db'
async function main() {
const cn = "DATABASE=SAMPLE;HOSTNAME=yadamu-db2;PORT=50000;PROTOCOL=TCPIP;UID=DB2INST1;PWD=oracle;"
const conn = await ibmdb.open(cn)
let results
results = await conn.query(`BEGIN DECLARE V_STATEMENT VARCHAR(300) DEFAULT 'drop table BINARY_TAB'; DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END; EXECUTE IMMEDIATE V_STATEMENT; END;`)
console.log(results)
results = await conn.querySync(`create table BINARY_TAB (id int, B1 BINARY(12), B2 BINARY(12), VB1 VARBINARY(12), VB2 VARBINARY(12) )`);
console.log(results)
const data = [
'628bac1ce075696504f012d4',
'628bac1ce075696504f012d5',
'628bac1ce075696504f012d6',
'628bac1ce075696504f012d7',
'628bac1ce075696504f012d8'
]
let idx=0
try {
const query = {
sql: `insert into BINARY_TAB (ID, B1, B2, VB1, VB2) values (?, ?, HEXTORAW(?), ?, HEXTORAW(?))`
, params: [{
ParamType: 'ARRAY',
DataType: 1,
Data: data.map(() => { return idx++ })
},{
ParamType: 'ARRAY',
DataType: 'BINARY',
Data: data.map((hex) => { return Buffer.from(hex,'hex')})
},{
ParamType: 'ARRAY',
DataType: 'VARCHAR',
Data: [...data],
Length: 24
},{
ParamType: 'ARRAY',
DataType: 'BINARY',
Data: data.map((hex) => { return Buffer.from(hex,'hex')})
},{
ParamType: 'ARRAY',
DataType: 'VARCHAR',
Data: [...data],
Length: 24
}]
, ArraySize: data.length
}
console.dir(query,{depth:null})
results = await conn.query(query);
console.log(results)
} catch (e) {
console.log(1,e)
}
results = await conn.query(`select ID, B1, B2, VB1, VB2 from BINARY_TAB`)
console.log("BINARY_TAB contents:\n", results);
results = await conn.query(`select ID, RAWTOHEX(B1) B1, RAWTOHEX(B2) B2, RAWTOHEX(VB1) VB1, RAWTOHEX(VB2) VB2 from BINARY_TAB`)
console.log("BINARY_TAB contents:\n", results);
}
main().then(() => { console.log('success')}).catch((e) => { console.log(e) })
Which produces the following output
C:\Development\YADAMU>node src\scratch\db2\binary.js
[]
[]
{
sql: 'insert into BINARY_TAB (ID, B1, B2, VB1, VB2) values (?, ?, HEXTORAW(?), ?, HEXTORAW(?))',
params: [
{ ParamType: 'ARRAY', DataType: 1, Data: [ 0, 1, 2, 3, 4 ] },
{
ParamType: 'ARRAY',
DataType: 'BINARY',
Data: [
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 212
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 213
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 214
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 215
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 216
]
]
},
{
ParamType: 'ARRAY',
DataType: 'VARCHAR',
Data: [
'628bac1ce075696504f012d4',
'628bac1ce075696504f012d5',
'628bac1ce075696504f012d6',
'628bac1ce075696504f012d7',
'628bac1ce075696504f012d8'
],
Length: 24
},
{
ParamType: 'ARRAY',
DataType: 'BINARY',
Data: [
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 212
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 213
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 214
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 215
],
Buffer(12) [Uint8Array] [
98, 139, 172, 28, 224,
117, 105, 101, 4, 240,
18, 216
]
]
},
{
ParamType: 'ARRAY',
DataType: 'VARCHAR',
Data: [
'628bac1ce075696504f012d4',
'628bac1ce075696504f012d5',
'628bac1ce075696504f012d6',
'628bac1ce075696504f012d7',
'628bac1ce075696504f012d8'
],
Length: 24
}
],
ArraySize: 5
}
[]
BINARY_TAB contents:
[
{
ID: 0,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D4',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D4'
},
{
ID: 1,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D5',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D5'
},
{
ID: 2,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D6',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D6'
},
{
ID: 3,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D7',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D7'
},
{
ID: 4,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D8',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D8'
}
]
BINARY_TAB contents:
[
{
ID: 0,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D4',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D4'
},
{
ID: 1,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D5',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D5'
},
{
ID: 2,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D6',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D6'
},
{
ID: 3,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D7',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D7'
},
{
ID: 4,
B1: '62FDFD1CFD75696504FD12FD',
B2: '628BAC1CE075696504F012D8',
VB1: '62FDFD1CFD75696504FD12FD',
VB2: '628BAC1CE075696504F012D8'
}
]
success
C:\Development\YADAMU>
If I pass a buffer columns B1 and VB1 do not round-trip. Based on the result of second select operation which coverts back to HEX inside the database it appears the values are not being written correctly.
Also, it appears that BINARY and VARBINARY is converted to HEX when it is retrieved.
Do I need to change the arguments to pass a Buffer as input without converting to HEX Can I get a Buffer back, rather than HEX ?
Can I pass HEX as input without needing to use HEXTORAW() ?
@markddrake I would suggest to use datatype as BLOB(12) for BINARY FOR BIT DATA in create table and pass the data as Buffer as shown here: https://github.com/ibmdb/node-ibm_db/blob/master/test/test-all-data-types.js#L75 Thanks.
Looking at the example it appears that the test passes column C18 as a BUFFER to the INSERT but the SELECT returns it as a string.
BTW this example also needs to be updated for the (highly questionable) behavior of returning BIGINT as number (Can we please have an OPTION to return bigint as STRING without having to add an explicit cast)
Also, I think this technique fails for the values > 0x7F...
See the following
import ibmdb from 'ibm_db'
import crypto from 'crypto';
import assert from 'assert';
async function main() {
const cn = "DATABASE=YADAMU;HOSTNAME=yadamu-db2;PORT=50000;PROTOCOL=TCPIP;UID=DB2INST1;PWD=oracle;"
const BLOB_LENGTH = 256;
const conn = await ibmdb.open(cn)
let results
results = await conn.query(`BEGIN DECLARE V_STATEMENT VARCHAR(300) DEFAULT 'drop table BLOB_TAB'; DECLARE CONTINUE HANDLER FOR SQLSTATE '42704' BEGIN END; EXECUTE IMMEDIATE V_STATEMENT; END;`)
console.log(results)
results = await conn.querySync(`create table BLOB_TAB (id int, B1 BLOB(${BLOB_LENGTH}))`);
console.log(results)
const values = Array.from(Array(BLOB_LENGTH).keys())
const buf = Buffer.from(values)
console.log(buf)
const blobParam = {DataType: "BLOB", Data:buf};
try {
const query = {
sql : `insert into BLOB_TAB (ID, B1) values (?, ?)`
, params: [1, blobParam]
}
results = await conn.query(query);
console.log(results)
} catch (e) {
console.log(1,e)
}
results = await conn.query(`select ID, length(B1) L1, B1 from BLOB_TAB`)
console.log(BLOB_LENGTH,results)
results.forEach((row,idx) => {
console.log(row.B1.length, Buffer.byteLength(row.B1), unescape(row.B1).length)
console.log(JSON.stringify(Buffer.from(unescape(row.B1))))
assert.equal(buf,Buffer.from(unescape(row.B1)))
})
}
main().then(() => { console.log('success')}).catch((e) => { console.log(e) })
results in
C:\Development\YADAMU>node src\scratch\db2\blob1.js
[]
[]
<Buffer 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d 1e 1f 20 21 22 23 24 25 26 27 28 29 2a 2b 2c 2d 2e 2f 30 31 ... 206 more bytes>
[]
256 [
{
ID: 1,
L1: 256,
B1: '\x00\x01\x02\x03\x04\x05\x06\x07\b\t\n' +
'\x0B\f\r\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F !"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7Fýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýý'
}
]
256 384 256
"\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýýý"
AssertionError [ERR_ASSERTION]: Buffer(256) [Uint8Array] [
There are two problems..
First the data is returned as a string which needs to converted back using the depricated 'unescape' function.
Second if the Buffer contains values > 0x7F, then the contents of the buffer are not written to the database correctly
db2 => select * from BLOB_TAB;
db2 (cont.) => /
ID B1
----------- -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 x'000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7FFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFDFD'
1 record(s) selected.
@markddrake we'll push the BIGINT fix soon. Thanks.
Opened #859 for Data Corruption issue
Opened #860 for the issue with the return type for BLOB columns
New bugs reports filed to address the two issues raised here.
Given the following table
What is the correct way to insert into a VARBINARY column, assuming I have a Buffer containing my content. I tried the following
and got
This worked
But converting buffers to hex and the converting them back again on the server seems a little inefficient ?