Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: SAP/node-hdb
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.19.12
Choose a base ref
...
head repository: SAP/node-hdb
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref
  • 8 commits
  • 30 files changed
  • 3 contributors

Commits on Jan 16, 2025

  1. Fixed 2 integration tests (#248)

    * Fixed 2 integration tests
    
    - Fixed SQL input which is not available in HANA cloud in the createReadNumbersProc testing setup function.
    - Also modified 'direct execute of ProcView with parameters' test to match the new change above for HANA cloud.
    - When not running on HANA cloud, the behavior is the same as before.
    
    * Fixed HANA cloud version check
    
    - Updated tests to consider versions starting with "4." as HANA cloud rather than "4.5"
    he-is-harry authored Jan 16, 2025
    Copy the full SHA
    f35c471 View commit details
  2. Support for data format version 4 datetime and alphanum types

    Add support for ALPHANUM, LONGDATE, SECONDDATE, DAYDATE, and
    SECONDTIME data types.
    IanMcCurdy authored Jan 16, 2025
    Copy the full SHA
    ffbfdd5 View commit details

Commits on Jan 20, 2025

  1. Copy the full SHA
    5cb6570 View commit details
  2. Merge pull request #252 from jeffalbion/serverversion

    Add fullVersionString and cloudVersionString to connectOptions
    jeffalbion authored Jan 20, 2025
    Copy the full SHA
    cd8a6a9 View commit details

Commits on Jan 21, 2025

  1. Added integration tests for data format version 4 types (#250)

    - Added integration tests for DAYDATE, SECONDDATE, LONGDATE, SECONDTIME, ALPHANUM, TEXT, and SHORTTEXT which only run when there is a valid remote DB
    - Added Gregorian calendar tests to the new date type integration tests
    - Updated the test remote db to obtain the HANA build version using the connect options reply instead of querying the db
    he-is-harry authored Jan 21, 2025
    Copy the full SHA
    71a7bfd View commit details
  2. Updated dataFormatVersion option to dataFormatSupport (#253)

    - Changed the name of the client config option dataFormatVersion to dataFormatSupport to match hana-client driver
    - Restricted dataFormatSupport versions to only those supported by the driver (1 - 4 for now). If versions that are not supported are entered in the config, an error will be sent.
    - Added unit tests to test the dataFormatSupport restrictions
    he-is-harry authored Jan 21, 2025
    Copy the full SHA
    3ff9c3e View commit details

Commits on Jan 28, 2025

  1. Added support for ST_GEOMETRY and ST_POINT (#255)

    - Added support for ST_GEOMETRY and ST_POINT by treating them as binary types
        - ST_GEOMETRY and ST_POINT can only be sent as buffers
    - Updated integration tests to only run data type tests when the required data format is met
    - Added integration tests for ST_GEOMETRY and ST_POINT
    he-is-harry authored Jan 28, 2025
    Copy the full SHA
    58eec9d View commit details

Commits on Jan 30, 2025

  1. Added spatialTypes connect option (#256)

    - 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
    he-is-harry authored Jan 30, 2025
    Copy the full SHA
    6f38a47 View commit details
44 changes: 36 additions & 8 deletions lib/protocol/Connection.js
Original file line number Diff line number Diff line change
@@ -26,6 +26,7 @@ var reply = require('./reply');
var createExecuteTask = require('./ExecuteTask').create;
var ReplySegment = reply.Segment;
var part = require('./part');
const DataFormatVersion = require('./common/DataFormatVersion');
var MessageType = common.MessageType;
var MessageTypeName = common.MessageTypeName;
var SegmentKind = common.SegmentKind;
@@ -42,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;

@@ -177,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;
}
}
});

@@ -457,15 +464,36 @@ Connection.prototype.connect = function connect(options, cb) {
}
delete options[key];
}
if(key.toUpperCase() === "DATAFORMATSUPPORT") {
if (options[key] && options[key] >= 1 && options[key] <= DataFormatVersion.MAX_VERSION) {
this.connectOptions.setOptions([
{name : common.ConnectOption.DATA_FORMAT_VERSION,
value : options[key]},
{name : common.ConnectOption.DATA_FORMAT_VERSION2,
value : options[key]}
]);
} else {
// Raise an error for the invalid data format version
if (options[key] > DataFormatVersion.MAX_VERSION) {
return cb(new Error(util.format("Maximum driver supported data format %d is less than client requested %d",
DataFormatVersion.MAX_VERSION, options[key])));
} else {
return cb(new Error(util.format("Data format %s is invalid. Supported values are 1 to %d",
options[key], DataFormatVersion.MAX_VERSION)));
}
}
} else if (key.toUpperCase() === 'SPATIALTYPES') {
this._settings['spatialTypes'] = util.getBooleanProperty(options[key]) ? 1 : 0;
}
}
this.connectOptions.setOptions([{
name : common.ConnectOption.OS_USER,
value : this._clientInfo.getUser()
}]);
this.clientContextOptions.setOptions([{
name : common.ClientContextOption.CLIENT_APPLICATION_PROGRAM,
value : this._clientInfo.getApplication()
}]);
this.connectOptions.setOptions([
{name : common.ConnectOption.OS_USER,
value : this._clientInfo.getUser()}
]);
this.clientContextOptions.setOptions([
{name : common.ClientContextOption.CLIENT_APPLICATION_PROGRAM,
value : this._clientInfo.getApplication()}
]);
if(options["disableCloudRedirect"] == true) {
this._redirectType = common.RedirectType.REDIRECTION_DISABLED;
}
2 changes: 1 addition & 1 deletion lib/protocol/ExecuteTask.js
Original file line number Diff line number Diff line change
@@ -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();
2 changes: 1 addition & 1 deletion lib/protocol/Parser.js
Original file line number Diff line number Diff line change
@@ -245,4 +245,4 @@ function getNestedMetadata(metadata, options) {
}
metadata.forEach(pushTableColumn);
return tables;
}
}
114 changes: 91 additions & 23 deletions lib/protocol/Reader.js
Original file line number Diff line number Diff line change
@@ -15,16 +15,20 @@

var util = require('../util');
var bignum = util.bignum;
var lpad2 = util.lpad2;
var lpad4 = util.lpad4;
var lrpad9 = util.lrpad9;
var common = require('./common');
var LobOptions = common.LobOptions;
var calendar = util.calendar;

module.exports = Reader;

function Reader(buffer, lobFactory, scrictEncoding) {
function Reader(buffer, lobFactory, strictEncoding) {
this.buffer = buffer;
this.offset = 0;
this.lobFactory = lobFactory;
this.scrictEncoding = scrictEncoding;
this.strictEncoding = strictEncoding;
}

Reader.prototype.hasMore = function hasMore() {
@@ -75,7 +79,9 @@ Reader.prototype.readBinary = function readBinary() {
return this.readBytes();
};

Reader.prototype.readBytes = function readBytes(isString) {
Reader.prototype.readBytes = function readBytes(isString, isAlphanum) {
const ALPHANUM_LENGTH_MASK = 0x7f;
const ALPHANUM_NUMERIC_VALUE = 0x80;
var length = this.buffer[this.offset++];
switch (length) {
case 0xff:
@@ -95,7 +101,21 @@ Reader.prototype.readBytes = function readBytes(isString) {
if (isString) {
value = util.convert.decode(
this.buffer.slice(this.offset, this.offset + length),
this.scrictEncoding);
this.strictEncoding);
} else if (isAlphanum) {
var ind = this.buffer[this.offset];
var newOffset = this.offset + 1;
var definitionLen = ind & ALPHANUM_LENGTH_MASK;
value = util.convert.decode(
this.buffer.slice(newOffset, newOffset + length - 1),
this.strictEncoding);
if (ind & ALPHANUM_NUMERIC_VALUE) {
// the value is purely numeric
if (definitionLen >= length) {
// zero-pad the value
value = "0".repeat(definitionLen - length + 1) + value;
}
}
} else {
value = new Buffer(length);
this.buffer.copy(value, 0, this.offset, this.offset + length);
@@ -123,8 +143,8 @@ Reader.prototype.readDate = function readDate() {
high &= 0x3f;
year |= high << 8;
return util.lpad4(year) + '-' +
util.lpad2(month) + '-' +
util.lpad2(day);
lpad2(month) + '-' +
lpad2(day);
};

Reader.prototype.readTime = function readTime() {
@@ -142,9 +162,9 @@ Reader.prototype.readTime = function readTime() {
// msb set ==> not null
// unset msb
hour &= 0x7f;
return util.lpad2(hour) + ':' +
util.lpad2(min) + ':' +
util.lpad2(msec / 1000);
return lpad2(hour) + ':' +
lpad2(min) + ':' +
lpad2(msec / 1000);
};

Reader.prototype.readTimestamp = function readTimestamp() {
@@ -163,12 +183,13 @@ Reader.prototype.readTimestamp = function readTimestamp() {
};

Reader.prototype.readDayDate = function readDayDate() {
var value = this.buffer.readInt32LE(this.offset);
var value = this.buffer.readUInt32LE(this.offset);
this.offset += 4;
if (value === 3652062 || value === 0) {
return null;
}
return value - 1;
var date = calendar.DATE(value);
return lpad4(date.y) + "-" + lpad2(date.m) + "-" + lpad2(date.d);
};

Reader.prototype.readSecondTime = function readSecondTime() {
@@ -177,7 +198,13 @@ Reader.prototype.readSecondTime = function readSecondTime() {
if (value === 86402 || value === 0) {
return null;
}
return value - 1;
value -= 1;
const seconds = value % 60;
value = ~~(value / 60);
const minutes = value % 60;
value = ~~(value / 60);
const hours = value;
return lpad2(hours) + ':' + lpad2(minutes) + ':' + lpad2(seconds);
};

Reader.prototype.readSecondDate = function readSecondDate() {
@@ -186,27 +213,64 @@ Reader.prototype.readSecondDate = function readSecondDate() {
if (value === 315538070401 || value === 0) {
return null;
}
return value - 1;
const dayFactor = 60 * 60 * 24;
var seconds, minutes, hours, day, month, year;
value -= 1;
var timeValue = value % dayFactor;
var dayDate = ~~(value / dayFactor) + 1;
var date = calendar.DATE(dayDate);
year = date.y;
month = date.m;
day = date.d;
seconds = timeValue % 60;
timeValue = ~~(timeValue / 60);
minutes = timeValue % 60;
hours = ~~(timeValue / 60);
var dateString = lpad4(year) + '-' + lpad2(month) + '-' + lpad2(day)
var timeString = lpad2(hours) + ':' + lpad2(minutes) + ':' + lpad2(seconds);
return dateString + ' ' + timeString;
};

Reader.prototype.readLongDate = function readLongDate() {
var value = bignum.readInt64LE(this.buffer, this.offset);
var seconds, minutes, hours, day, month, year;
const dayFactor = 60 * 60 * 24;
this.offset += 8;
if (value === '3155380704000000001' || value === 0) {
return null;
}
var fractionalSeconds, secondDate;

if (typeof value === 'string') {
/* FIXME */
var index = value.length - 7;
var secondDate = parseInt(value.substring(0, index), 10);
var fractionalSeconds = parseInt(value.substring(index), 10) - 1;
if (fractionalSeconds < 0) {
fractionalSeconds = 9999999;
secondDate -= 1;
}
return secondDate + util.lpad7(fractionalSeconds);
secondDate = parseInt(value.substring(0, index), 10);
fractionalSeconds = parseInt(value.substring(index), 10);
} else {
secondDate = ~~(value / 10000000);
fractionalSeconds = value % 10000000;
}
return value - 1;

if (fractionalSeconds == 0) {
fractionalSeconds = 9999999;
secondDate -= 1;
} else {
fractionalSeconds -= 1;
}
var timeValue = secondDate % dayFactor;
var dayDate = ~~(secondDate / dayFactor) + 1;
seconds = timeValue % 60;
timeValue = ~~(timeValue / 60);
minutes = timeValue % 60;
timeValue = ~~(timeValue / 60);
hours = timeValue;

var date = calendar.DATE(dayDate);
day = date.d;
month = date.m;
year = date.y;
var dateString = lpad4(year) + '-' + lpad2(month) + '-' + lpad2(day)
var timeString = lpad2(hours) + ':' + lpad2(minutes) + ':' + lpad2(seconds) + '.' + lrpad9(fractionalSeconds);
return dateString + ' ' + timeString;
};

Reader.prototype.readBLob = function readBLob() {
@@ -301,6 +365,10 @@ Reader.prototype.readDecimal = function readDecimal(fraction) {
return value;
};

Reader.prototype.readAlphanum = function readAlphanum() {
return this.readBytes(false, true);
}

Reader.LobDescriptor = LobDescriptor;

function LobDescriptor(type, options, charLength, byteLength, locatorId, chunk, defaultType) {
@@ -320,4 +388,4 @@ Object.defineProperties(LobDescriptor.prototype, {
return !!(this.options & LobOptions.LAST_DATA);
}
}
});
});
Loading