UNPKG

oracledb

Version:

A Node.js module for Oracle Database access from JavaScript and TypeScript

213 lines (202 loc) 6.65 kB
// Copyright (c) 2022, 2023, Oracle and/or its affiliates. //----------------------------------------------------------------------------- // // This software is dual-licensed to you under the Universal Permissive License // (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License // 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose // either license. // // If you elect to accept the software under the Apache License, Version 2.0, // the following applies: // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //----------------------------------------------------------------------------- 'use strict'; const { Buffer } = require('buffer'); const constants = require('../constants.js'); const Message = require('./base.js'); /** * Abstracts all LOB operations. * * @class LobOpMessage * @extends {Message} */ class LobOpMessage extends Message { constructor(connImpl, options) { super(connImpl); /* * source LOB locator. Reading data from it. */ this.sourceLobImpl = options.sourceLobImpl || null; this.operation = options.operation; /* * Destination LOB locator. For copy, append operations,... */ this.destLobImpl = options.destLobImpl || null; /* * Offset from where sourceLob operation to start */ this.sourceOffset = options.sourceOffset || 0; /* * Offset from where destLob operation to start */ this.destOffset = options.destOffset || 0; this.boolFlag = false; if (options.data) { // data available For Writes this.data = options.data; } this.functionCode = constants.TNS_FUNC_LOB_OP; this.sendAmount = options.sendAmount; this.amount = options.amount || 0; // LOB length } encode(buf) { this.writeFunctionHeader(buf); if (this.sourceLobImpl === null) { buf.writeUInt8(0); buf.writeUB4(0); } else { buf.writeUInt8(1); buf.writeUB4(this.sourceLobImpl._locator.length); } if (this.destLobImpl === null) { buf.writeUInt8(0); buf.writeUB4(0); } else { buf.writeUInt8(1); buf.writeUB4(this.destLobImpl._locator.length); } buf.writeUB4(0); buf.writeUB4(0); if (this.operation === constants.TNS_LOB_OP_CREATE_TEMP) { buf.writeUInt8(1); } else { buf.writeUInt8(0); } buf.writeUInt8(0); const operations = [ constants.TNS_LOB_OP_CREATE_TEMP, constants.TNS_LOB_OP_IS_OPEN, constants.TNS_LOB_OP_FILE_EXISTS, constants.TNS_LOB_OP_FILE_ISOPEN, ]; if (operations.includes(this.operation)) { buf.writeUInt8(1); } else { buf.writeUInt8(0); } buf.writeUB4(this.operation); buf.writeUInt8(0); buf.writeUInt8(0); buf.writeUB8(this.sourceOffset); buf.writeUB8(this.destOffset); if (this.sendAmount) { buf.writeUInt8(1); } else { buf.writeUInt8(0); } for (let i = 0; i < 3; i++) { buf.writeUInt16BE(0); } if (this.sourceLobImpl) { buf.writeBytes(this.sourceLobImpl._locator); } if (this.destLobImpl) { buf.writeBytes(this.destLobImpl._locator); } if (this.operation === constants.TNS_LOB_OP_CREATE_TEMP) { if (this.sourceLobImpl.dbType._csfrm === constants.CSFRM_NCHAR) { buf.caps.checkNCharsetId(); buf.writeUB4(constants.TNS_CHARSET_UTF16); } else { buf.writeUB4(constants.TNS_CHARSET_UTF8); } } if (this.data) { let data; buf.writeUInt8(constants.TNS_MSG_TYPE_LOB_DATA); if (this.sourceLobImpl.dbType._oraTypeNum === constants.TNS_DATA_TYPE_BLOB) { data = this.data; } else if (this.sourceLobImpl.getCsfrm() === constants.CSFRM_NCHAR) { data = this.data; // TODO: avoid conversion back to string, if possible // this is since bind data is converted to buffer automatically, but if // it exceeds 32K for PL/SQL it must be written as a temporary LOB if (Buffer.isBuffer(this.data)) { data = data.toString(); } data = Buffer.from(data, constants.TNS_ENCODING_UTF16).swap16(); } else { data = Buffer.from(this.data); } buf.writeBytesWithLength(data); } if (this.sendAmount) { buf.writeUB8(this.amount); } } processMessage(buf, messageType) { if (messageType === constants.TNS_MSG_TYPE_LOB_DATA) { const oraTypeNum = this.sourceLobImpl.dbType._oraTypeNum; let data = buf.readBytesWithLength(); if (data !== null) { if ( oraTypeNum === constants.TNS_DATA_TYPE_BLOB || oraTypeNum === constants.TNS_DATA_TYPE_BFILE ) { data = Buffer.from(data); } else if (this.sourceLobImpl.getCsfrm() === constants.CSFRM_NCHAR) { data = Buffer.from(data).swap16().toString('utf16le'); } else { data = data.toString(); } } this.data = data; } else { super.processMessage(buf, messageType); } } processReturnParameter(buf) { let lobArray; let locator; let temp8; let numBytes; if (this.sourceLobImpl !== null) { numBytes = this.sourceLobImpl._locator.length; lobArray = buf.readBytes(numBytes); locator = lobArray.slice(0, numBytes); locator.copy(this.sourceLobImpl._locator); } if (this.destLobImpl !== null) { numBytes = this.destLobImpl._locator.length; lobArray = buf.readBytes(numBytes); locator = lobArray.slice(0, numBytes); locator.copy(this.destLobImpl._locator); } if (this.operation === constants.TNS_LOB_OP_CREATE_TEMP) { buf.skipUB2(); // skip character set buf.skipBytes(3); // skip trailing flags, amount } else if (this.sendAmount) { this.amount = buf.readSB8(); } if ( this.operation === constants.TNS_LOB_OP_IS_OPEN || this.operation === constants.TNS_LOB_OP_FILE_EXISTS || this.operation === constants.TNS_LOB_OP_FILE_ISOPEN ) { temp8 = buf.readUInt8(); this.boolFlag = temp8 > 0; } } } module.exports = LobOpMessage;