'use strict'; const ResultSet = require('./resultset'); class CommonBinary extends ResultSet { constructor(resolve, reject, cmdOpts, connOpts, sql, values) { super(resolve, reject); this.configAssign(connOpts, cmdOpts); this.sql = sql; this.initialValues = values; } /** * 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 */ writeParam(out, value, opts, info) { let flushed = false; switch (typeof value) { case 'boolean': flushed = out.writeInt8(0x00); flushed = out.writeInt8(value ? 0x01 : 0x00) || flushed; break; case 'bigint': case 'number': flushed = out.writeInt8(0x00); flushed = out.writeLengthStringAscii('' + value) || flushed; break; case 'object': if (Object.prototype.toString.call(value) === '[object Date]') { flushed = out.writeInt8(0x00); flushed = out.writeBinaryDate(value, opts) || flushed; } else if (Buffer.isBuffer(value)) { flushed = out.writeInt8(0x00); flushed = out.writeLengthEncodedBuffer(value) || flushed; } else if (typeof value.toSqlString === 'function') { flushed = out.writeInt8(0x00); flushed = out.writeLengthEncodedString(String(value.toSqlString())) || flushed; } else { if ( value.type != null && [ 'Point', 'LineString', 'Polygon', 'MultiPoint', 'MultiLineString', 'MultiPolygon', 'GeometryCollection' ].includes(value.type) ) { const geoBuff = this.getBufferFromGeometryValue(value); if (geoBuff) { flushed = out.writeInt8(0x00); //Value follow flushed = out.writeLengthEncodedBuffer(Buffer.concat([Buffer.from([0, 0, 0, 0]), geoBuff])) || flushed; } else { flushed = out.writeInt8(0x01); //NULL } } else { //TODO check if permitSetMultiParamEntries is needed !? flushed = out.writeInt8(0x00); flushed = out.writeLengthEncodedString(JSON.stringify(value)) || flushed; } } break; default: flushed = out.writeInt8(0x00); flushed = out.writeLengthEncodedString(value) || flushed; } return flushed; } 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; } } /** * Read text result-set row * * see: https://mariadb.com/kb/en/library/resultset-row/#text-resultset-row * data are created according to their type. * * @param columns columns metadata * @param packet current row packet * @param connOpts connection options * @returns {*} row data */ parseRow(columns, packet, connOpts) { throw new Error('not implemented'); } } module.exports = CommonBinary;