Files
lcbp3.np-dms.work/backend/node_modules/mariadb/lib/cmd/encoder/binary-encoder.js
2025-09-21 20:29:15 +07:00

285 lines
9.9 KiB
JavaScript
Executable File

// SPDX-License-Identifier: LGPL-2.1-or-later
// Copyright (c) 2015-2024 MariaDB Corporation Ab
'use strict';
class BinaryEncoder {
/**
* Write (and escape) current parameter value to output writer
*
* @param out output writer
* @param value current parameter
* @param opts connection options
* @param info connection information
*/
static writeParam(out, value, opts, info) {
// GEOJSON are not checked, because change to null/Buffer on parameter validation
switch (typeof value) {
case 'boolean':
out.writeInt8(value ? 0x01 : 0x00);
break;
case 'bigint':
if (value >= 2n ** 63n) {
out.writeLengthEncodedString(value.toString());
} else {
out.writeBigInt(value);
}
break;
case 'number':
// additional verification, to permit query without type,
// like 'SELECT ?' returning same type of value
if (Number.isInteger(value) && value >= -2147483648 && value < 2147483647) {
out.writeInt32(value);
break;
}
out.writeDouble(value);
break;
case 'string':
out.writeLengthEncodedString(value);
break;
case 'object':
if (Object.prototype.toString.call(value) === '[object Date]') {
out.writeBinaryDate(value);
} else if (Buffer.isBuffer(value)) {
out.writeLengthEncodedBuffer(value);
} else if (typeof value.toSqlString === 'function') {
out.writeLengthEncodedString(String(value.toSqlString()));
} else {
out.writeLengthEncodedString(JSON.stringify(value));
}
break;
default:
out.writeLengthEncodedBuffer(value);
}
}
static getBufferFromGeometryValue(value, headerType) {
let geoBuff;
let pos;
let type;
if (!headerType) {
switch (value.type) {
case 'Point':
geoBuff = Buffer.allocUnsafe(21);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(1, 1); //wkbPoint
if (
value.coordinates &&
Array.isArray(value.coordinates) &&
value.coordinates.length >= 2 &&
!isNaN(value.coordinates[0]) &&
!isNaN(value.coordinates[1])
) {
geoBuff.writeDoubleLE(value.coordinates[0], 5); //X
geoBuff.writeDoubleLE(value.coordinates[1], 13); //Y
return geoBuff;
} else {
return null;
}
case 'LineString':
if (value.coordinates && Array.isArray(value.coordinates)) {
const pointNumber = value.coordinates.length;
geoBuff = Buffer.allocUnsafe(9 + 16 * pointNumber);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(2, 1); //wkbLineString
geoBuff.writeInt32LE(pointNumber, 5);
for (let i = 0; i < pointNumber; i++) {
if (
value.coordinates[i] &&
Array.isArray(value.coordinates[i]) &&
value.coordinates[i].length >= 2 &&
!isNaN(value.coordinates[i][0]) &&
!isNaN(value.coordinates[i][1])
) {
geoBuff.writeDoubleLE(value.coordinates[i][0], 9 + 16 * i); //X
geoBuff.writeDoubleLE(value.coordinates[i][1], 17 + 16 * i); //Y
} else {
return null;
}
}
return geoBuff;
} else {
return null;
}
case 'Polygon':
if (value.coordinates && Array.isArray(value.coordinates)) {
const numRings = value.coordinates.length;
let size = 0;
for (let i = 0; i < numRings; i++) {
size += 4 + 16 * value.coordinates[i].length;
}
geoBuff = Buffer.allocUnsafe(9 + size);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(3, 1); //wkbPolygon
geoBuff.writeInt32LE(numRings, 5);
pos = 9;
for (let i = 0; i < numRings; i++) {
const lineString = value.coordinates[i];
if (lineString && Array.isArray(lineString)) {
geoBuff.writeInt32LE(lineString.length, pos);
pos += 4;
for (let j = 0; j < lineString.length; j++) {
if (
lineString[j] &&
Array.isArray(lineString[j]) &&
lineString[j].length >= 2 &&
!isNaN(lineString[j][0]) &&
!isNaN(lineString[j][1])
) {
geoBuff.writeDoubleLE(lineString[j][0], pos); //X
geoBuff.writeDoubleLE(lineString[j][1], pos + 8); //Y
pos += 16;
} else {
return null;
}
}
}
}
return geoBuff;
} else {
return null;
}
case 'MultiPoint':
type = 'MultiPoint';
geoBuff = Buffer.allocUnsafe(9);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(4, 1); //wkbMultiPoint
break;
case 'MultiLineString':
type = 'MultiLineString';
geoBuff = Buffer.allocUnsafe(9);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(5, 1); //wkbMultiLineString
break;
case 'MultiPolygon':
type = 'MultiPolygon';
geoBuff = Buffer.allocUnsafe(9);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(6, 1); //wkbMultiPolygon
break;
case 'GeometryCollection':
geoBuff = Buffer.allocUnsafe(9);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(7, 1); //wkbGeometryCollection
if (value.geometries && Array.isArray(value.geometries)) {
const coordinateLength = value.geometries.length;
const subArrays = [geoBuff];
for (let i = 0; i < coordinateLength; i++) {
const tmpBuf = this.getBufferFromGeometryValue(value.geometries[i]);
if (tmpBuf == null) break;
subArrays.push(tmpBuf);
}
geoBuff.writeInt32LE(subArrays.length - 1, 5);
return Buffer.concat(subArrays);
} else {
geoBuff.writeInt32LE(0, 5);
return geoBuff;
}
default:
return null;
}
if (value.coordinates && Array.isArray(value.coordinates)) {
const coordinateLength = value.coordinates.length;
const subArrays = [geoBuff];
for (let i = 0; i < coordinateLength; i++) {
const tmpBuf = this.getBufferFromGeometryValue(value.coordinates[i], type);
if (tmpBuf == null) break;
subArrays.push(tmpBuf);
}
geoBuff.writeInt32LE(subArrays.length - 1, 5);
return Buffer.concat(subArrays);
} else {
geoBuff.writeInt32LE(0, 5);
return geoBuff;
}
} else {
switch (headerType) {
case 'MultiPoint':
if (value && Array.isArray(value) && value.length >= 2 && !isNaN(value[0]) && !isNaN(value[1])) {
geoBuff = Buffer.allocUnsafe(21);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(1, 1); //wkbPoint
geoBuff.writeDoubleLE(value[0], 5); //X
geoBuff.writeDoubleLE(value[1], 13); //Y
return geoBuff;
}
return null;
case 'MultiLineString':
if (value && Array.isArray(value)) {
const pointNumber = value.length;
geoBuff = Buffer.allocUnsafe(9 + 16 * pointNumber);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(2, 1); //wkbLineString
geoBuff.writeInt32LE(pointNumber, 5);
for (let i = 0; i < pointNumber; i++) {
if (
value[i] &&
Array.isArray(value[i]) &&
value[i].length >= 2 &&
!isNaN(value[i][0]) &&
!isNaN(value[i][1])
) {
geoBuff.writeDoubleLE(value[i][0], 9 + 16 * i); //X
geoBuff.writeDoubleLE(value[i][1], 17 + 16 * i); //Y
} else {
return null;
}
}
return geoBuff;
}
return null;
case 'MultiPolygon':
if (value && Array.isArray(value)) {
const numRings = value.length;
let size = 0;
for (let i = 0; i < numRings; i++) {
size += 4 + 16 * value[i].length;
}
geoBuff = Buffer.allocUnsafe(9 + size);
geoBuff.writeInt8(0x01, 0); //LITTLE ENDIAN
geoBuff.writeInt32LE(3, 1); //wkbPolygon
geoBuff.writeInt32LE(numRings, 5);
pos = 9;
for (let i = 0; i < numRings; i++) {
const lineString = value[i];
if (lineString && Array.isArray(lineString)) {
geoBuff.writeInt32LE(lineString.length, pos);
pos += 4;
for (let j = 0; j < lineString.length; j++) {
if (
lineString[j] &&
Array.isArray(lineString[j]) &&
lineString[j].length >= 2 &&
!isNaN(lineString[j][0]) &&
!isNaN(lineString[j][1])
) {
geoBuff.writeDoubleLE(lineString[j][0], pos); //X
geoBuff.writeDoubleLE(lineString[j][1], pos + 8); //Y
pos += 16;
} else {
return null;
}
}
}
}
return geoBuff;
}
return null;
}
return null;
}
}
}
module.exports = BinaryEncoder;