Skip to content

Commit

Permalink
Added spatialTypes connect option (#256)
Browse files Browse the repository at this point in the history
- Added spatialTypes option to allow strings to be sent for spatial types
    - With spatialTypes=0 (default), strings inputted for ST_GEOMETRY and ST_POINT are interpreted as hex
    - With spatialTypes=1, strings inputted for ST_GEOMETRY and ST_POINT can be encoded in utf8 or cesu8
    - Buffers can be sent in any of these options and will be interpreted as binary
- Added integration tests to check inserting and fetching large ST_GEOMETRY data
- Added some integration tests to check the spatialTypes=1 behaviour
  • Loading branch information
he-is-harry authored Jan 30, 2025
1 parent 58eec9d commit 6f38a47
Show file tree
Hide file tree
Showing 7 changed files with 284 additions and 71 deletions.
8 changes: 8 additions & 0 deletions lib/protocol/Connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ var MAXIMUM_PACKET_SIZE = common.MAXIMUM_PACKET_SIZE;
var PACKET_HEADER_LENGTH = common.PACKET_HEADER_LENGTH;
var SEGMENT_HEADER_LENGTH = common.SEGMENT_HEADER_LENGTH;
var PART_HEADER_LENGTH = common.PART_HEADER_LENGTH;
var DEFAULT_SPATIAL_TYPES = common.DEFAULT_SPATIAL_TYPES;

module.exports = Connection;

Expand Down Expand Up @@ -178,6 +179,11 @@ Object.defineProperties(Connection.prototype, {
limit = Math.max(limit, this.packetSize);
return limit;
}
},
spatialTypes: {
get: function getSpatialTypes() {
return this._settings.spatialTypes || DEFAULT_SPATIAL_TYPES;
}
}
});

Expand Down Expand Up @@ -476,6 +482,8 @@ Connection.prototype.connect = function connect(options, cb) {
options[key], DataFormatVersion.MAX_VERSION)));
}
}
} else if (key.toUpperCase() === 'SPATIALTYPES') {
this._settings['spatialTypes'] = util.getBooleanProperty(options[key]) ? 1 : 0;
}
}
this.connectOptions.setOptions([
Expand Down
2 changes: 1 addition & 1 deletion lib/protocol/ExecuteTask.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ function ExecuteTask(connection, options, callback) {
this.scrollableCursor = options.scrollableCursor;
this.statementId = options.statementId;
this.functionCode = options.functionCode;
this.writer = new Writer(options.parameters.types, connection.useCesu8);
this.writer = new Writer(options.parameters.types, connection.useCesu8, connection.spatialTypes);
var values = options.parameters.values;
if (values.length && Array.isArray(values[0])) {
this.parameterValues = values.slice();
Expand Down
24 changes: 21 additions & 3 deletions lib/protocol/Writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,11 @@ var REGEX = {

const maxDecimalMantissaLen = 34;

function Writer(types, useCesu8) {
function Writer(types, useCesu8, spatialTypes) {
this._types = types.map(normalizeType);
this.reset();
this._useCesu8 = (useCesu8 === true);
this._spatialTypes = (spatialTypes === 1 ? 1 : 0);
}

function normalizeType(type) {
Expand All @@ -70,8 +71,8 @@ Writer.prototype.setValues = function setValues(values) {
this._params = true;
};

exports.create = function createWriter(params, useCesu8) {
var writer = new Writer(params.types, useCesu8);
exports.create = function createWriter(params, useCesu8, spatialTypes) {
var writer = new Writer(params.types, useCesu8, spatialTypes);
writer.setValues(params.values);
return writer;
};
Expand Down Expand Up @@ -397,6 +398,9 @@ Writer.prototype.pushNull = function pushNull(type) {
case TypeCode.SECONDTIME:
nullTypeCode = TypeCode.TIME | 0x80;
break;
case TypeCode.ST_GEOMETRY:
nullTypeCode = TypeCode.BINARY | 0x80;
break;
default:
nullTypeCode = NormalizedTypeCode[type] | 0x80;
}
Expand Down Expand Up @@ -754,6 +758,20 @@ Writer.prototype[TypeCode.SECONDDATE] = function writeSecondDate(value) {
this.push(buffer);
};

Writer.prototype[TypeCode.ST_GEOMETRY] = function writeST_GEOMETRY(value) {
if (Buffer.isBuffer(value)) {
this.push(createBinaryOutBuffer(TypeCode.BINARY, value));
} else if (util.isString(value)) {
if (this._spatialTypes === 1) {
this.writeCharacters(TypeCode.STRING, value);
} else {
this.push(createBinaryOutBuffer(TypeCode.BINARY, Buffer.from(value, 'hex')));
}
} else {
throw new TypeError('Argument must be a string or Buffer');
}
}

function setChar(str, i, c) {
if(i >= str.length) return str;
return str.substring(0, i) + c + str.substring(i + 1);
Expand Down
1 change: 1 addition & 0 deletions lib/protocol/common/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = {
DATA_LENGTH_MAX2BYTE_LENGTH: 32767,
DATA_LENGTH_2BYTE_LENGTH_INDICATOR: 246,
DATA_LENGTH_4BYTE_LENGTH_INDICATOR: 247,
DEFAULT_SPATIAL_TYPES: 0,
DEFAULT_CONNECT_OPTIONS: [{
name: ConnectOption.CLIENT_LOCALE,
value: 'en_US',
Expand Down
5 changes: 3 additions & 2 deletions lib/protocol/common/NormalizedTypeCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,6 @@ NormalizedTypeCode[TypeCode.NSTRING] = TypeCode.NSTRING;
NormalizedTypeCode[TypeCode.BINARY] = TypeCode.BINARY;
NormalizedTypeCode[TypeCode.VARBINARY] = TypeCode.BINARY;
NormalizedTypeCode[TypeCode.BSTRING] = TypeCode.BINARY;
NormalizedTypeCode[TypeCode.ST_GEOMETRY] = TypeCode.BINARY;
NormalizedTypeCode[TypeCode.ST_POINT] = TypeCode.BINARY;
// BLob
NormalizedTypeCode[TypeCode.BLOB] = TypeCode.BLOB;
NormalizedTypeCode[TypeCode.LOCATOR] = TypeCode.BLOB;
Expand All @@ -70,3 +68,6 @@ NormalizedTypeCode[TypeCode.SECONDTIME] = TypeCode.SECONDTIME;
NormalizedTypeCode[TypeCode.LONGDATE] = TypeCode.LONGDATE;
// SecondDate
NormalizedTypeCode[TypeCode.SECONDDATE] = TypeCode.SECONDDATE;
// ST_GEOMETRY
NormalizedTypeCode[TypeCode.ST_GEOMETRY] = TypeCode.ST_GEOMETRY;
NormalizedTypeCode[TypeCode.ST_POINT] = TypeCode.ST_GEOMETRY;
15 changes: 15 additions & 0 deletions lib/util/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -265,3 +265,18 @@ function filter(keys) {
return obj;
}
exports.filter = filter;

function getBooleanProperty(arg) {
if (isString(arg)) {
var upper = arg.toUpperCase();
if (upper === 'TRUE' || upper === 'YES' || upper === 'ON' || upper === '1') {
return true;
}
return false;
} else if (arg === 1) {
return true;
} else {
return false;
}
}
exports.getBooleanProperty = getBooleanProperty;
Loading

0 comments on commit 6f38a47

Please sign in to comment.