Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add support for bigints (backport of #14485) #15413

Merged
merged 10 commits into from
Dec 12, 2022
30 changes: 19 additions & 11 deletions src/dialects/oracle/data-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,18 @@ module.exports = BaseTypes => {
// sending it over the wire as a string,
// We pass it through escape function to remove un-necessary quotes
// this.format in insert/bulkinsert query calls stringify hence we need to convert binary buffer
// to hex string. Since this block is used by both bind (insert/bulkinsert) and
// non-bind (select query where clause) hence we need to
// to hex string. Since this block is used by both bind (insert/bulkinsert) and
// non-bind (select query where clause) hence we need to
// have an operation that supports both
return options.escape(value.toString('hex'));
}
}
return options.escape(value);
}

_getBindDef(oracledb) {
if (this._binary) {
return { type: oracledb.DB_TYPE_RAW, maxSize: this._length };
}
}
return { type: oracledb.DB_TYPE_VARCHAR, maxSize: this._length };
}

Expand Down Expand Up @@ -93,7 +93,7 @@ module.exports = BaseTypes => {

_sanitize(value) {
if (typeof value === 'string') {
// If value is a string we return true if among '1' and 'true'
// If value is a string we return true if among '1' and 'true'
// We return false if among '0' and 'false'
// Else return the value as is and let the DB raise error for invalid values
return value === '1' || value === 'true' ? true : value === '0' || value === 'false' ? false : value;
Expand Down Expand Up @@ -212,7 +212,7 @@ module.exports = BaseTypes => {
*/
_bindParam(value, options) {
return options.bindParam(value);
}
}
}

DATE.prototype.escape = false;
Expand Down Expand Up @@ -302,6 +302,14 @@ module.exports = BaseTypes => {
_getBindDef(oracledb) {
marra85 marked this conversation as resolved.
Show resolved Hide resolved
return { type: oracledb.DB_TYPE_NUMBER };
}

_sanitize(value) {
if (typeof value === 'bigint' || typeof value === 'number') {
return value.toString();
}
return value;
}

}

class NUMBER extends BaseTypes.NUMBER {
Expand Down Expand Up @@ -335,7 +343,7 @@ module.exports = BaseTypes => {
_stringify(value) {
if (value === Number.POSITIVE_INFINITY) {
return 'inf';
}
}
if (value === Number.NEGATIVE_INFINITY) {
return '-inf';
}
Expand All @@ -348,11 +356,11 @@ module.exports = BaseTypes => {
}

class BLOB extends BaseTypes.BLOB {
// Generic hexify returns X'${hex}' but Oracle expects '${hex}' for BLOB datatype
// Generic hexify returns X'${hex}' but Oracle expects '${hex}' for BLOB datatype
_hexify(hex) {
return `'${hex}'`;
}

toSql() {
return 'BLOB';
}
Expand Down Expand Up @@ -438,9 +446,9 @@ module.exports = BaseTypes => {
_bindParam(value, options) {
if (typeof value === 'string') {
return options.bindParam(new Date(value));
}
}
return options.bindParam(value);

}
}

Expand Down
53 changes: 33 additions & 20 deletions src/dialects/oracle/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,6 @@ const { logger } = require('../../utils/logger');

const debug = logger.debugContext('sql:oracle');

function stringifyIfBigint(value) {
if (typeof value === 'bigint') {
return value.toString();
}
return value;
}

export class OracleQuery extends AbstractQuery {
constructor(connection, sequelize, options) {
super(connection, sequelize, options);
Expand All @@ -44,7 +37,7 @@ export class OracleQuery extends AbstractQuery {
// We set the oracledb
const oracledb = this.sequelize.connectionManager.lib;

if (this.isSelectQuery() && this.model) {
if (this.model && this.isSelectQuery()) {
const fInfo = {};
const keys = Object.keys(this.model.tableAttributes);
for (const key of keys) {
Expand All @@ -63,6 +56,35 @@ export class OracleQuery extends AbstractQuery {
}
return execOpts;
}

/**
* convert binding values for unsupported
marra85 marked this conversation as resolved.
Show resolved Hide resolved
* types in connector library
*
* @param {string} bindingDictionary a string representing the key to scan
* @param {object} oracledb native oracle library
* @private
*/
_convertBindAttributes(bindingDictionary, oracledb) {
if (this.model && this.options[bindingDictionary]) {
// check against model if we have some BIGINT
const keys = Object.keys(this.model.tableAttributes);
for (const key of keys) {
const keyValue = this.model.tableAttributes[key];
if (keyValue.type.key === 'BIGINT') {
const oldBinding = this.options[bindingDictionary][key];
if (oldBinding) {
this.options[bindingDictionary][key] = {
...oldBinding,
type: oracledb.STRING,
maxSize: 10000000 //TOTALLY ARBITRARY Number to prevent query failure
};
}
}
}
}
}

async run(sql, parameters) {
// We set the oracledb
const oracledb = this.sequelize.connectionManager.lib;
Expand All @@ -77,21 +99,10 @@ export class OracleQuery extends AbstractQuery {
this.sql = sql;
}

// Since the bigint primitive is not automatically translated
// we stringify the value as was done previously
if (_.isPlainObject(parameters)) {
const newParameters = Object.create(null);
for (const key of Object.keys(parameters)) {
newParameters[`${key}`] = stringifyIfBigint(parameters[key]);
}
parameters = newParameters;
} else if (_.isArray(parameters)) {
parameters = parameters.map(stringifyIfBigint);
}

// When this.options.bindAttributes exists then it is an insertQuery/upsertQuery
// So we insert the return bind direction and type
if (this.options.outBindAttributes && (Array.isArray(parameters) || _.isPlainObject(parameters))) {
this._convertBindAttributes('outBindAttributes', oracledb);
outParameters.push(...Object.values(this.options.outBindAttributes));
// For upsertQuery we need to push the bindDef for isUpdate
if (this.isUpsertQuery()) {
Expand All @@ -106,6 +117,7 @@ export class OracleQuery extends AbstractQuery {
if (this.options.executeMany) {
// Constructing BindDefs for ExecuteMany call
// Building the bindDef for in and out binds
this._convertBindAttributes('inbindAttributes', oracledb);
bindDef.push(...Object.values(this.options.inbindAttributes));
bindDef.push(...outParameters);
this.bindParameters = parameters;
Expand Down Expand Up @@ -242,6 +254,7 @@ export class OracleQuery extends AbstractQuery {
* @param {string} dialect
*/
static formatBindParameters(sql, values, dialect) {

const replacementFunc = (match, key, values) => {
if (values[key] !== undefined) {
return `:${key}`;
Expand Down