248 lines
7.8 KiB
JavaScript
248 lines
7.8 KiB
JavaScript
// Copyright (c) 2016, 2021, Oracle and/or its affiliates. All rights reserved
|
|
|
|
//-----------------------------------------------------------------------------
|
|
//
|
|
// You may not use the identified files except in compliance with the Apache
|
|
// License, Version 2.0 (the "License.")
|
|
//
|
|
// You may obtain a copy of the License at
|
|
// http://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 QueryStream = require('./queryStream.js');
|
|
const nodbUtil = require('./util.js');
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// close()
|
|
// Close the result set and make it unusable for further operations.
|
|
//-----------------------------------------------------------------------------
|
|
async function close() {
|
|
nodbUtil.checkArgCount(arguments, 0, 0);
|
|
|
|
if (this._convertedToStream) {
|
|
throw new Error(nodbUtil.getErrorMessage('NJS-042'));
|
|
}
|
|
|
|
this._processingStarted = true;
|
|
await this._close();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// getRow()
|
|
// Returns a single row to the caller from the result set, if one is
|
|
// available. Rows are buffered in a JavaScript array in order to avoid trips
|
|
// through the thread pool that would be required if implemented in C.
|
|
//-----------------------------------------------------------------------------
|
|
async function getRow() {
|
|
nodbUtil.checkArgCount(arguments, 0, 0);
|
|
|
|
if (this._convertedToStream && !this._allowGetRowCall) {
|
|
throw new Error(nodbUtil.getErrorMessage('NJS-042'));
|
|
}
|
|
|
|
this._allowGetRowCall = false;
|
|
this._processingStarted = true;
|
|
|
|
if (this._rowCache.length == 0) {
|
|
this._rowCache = await this._getRows(this._fetchArraySize, false, false);
|
|
}
|
|
return this._rowCache.shift();
|
|
}
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// getRows()
|
|
// Check to see if any rows are in the JS buffer (which could result from
|
|
// interspersed calls to getRow() and getRows()). If no rows are in the buffer
|
|
// buffer, the call is just proxied to the C layer. Otherwise, rows are pulled
|
|
// from the buffer and potentially concatenated with rows from a call to
|
|
// getRows().
|
|
//-----------------------------------------------------------------------------
|
|
async function getRows(numRows) {
|
|
let rowsNeeded;
|
|
|
|
nodbUtil.checkArgCount(arguments, 0, 1);
|
|
|
|
if (arguments.length == 0) {
|
|
numRows = 0;
|
|
} else {
|
|
nodbUtil.assert(Number.isInteger(numRows), 'NJS-005', 1);
|
|
nodbUtil.assert(numRows >= 0, 'NJS-005', 1);
|
|
}
|
|
|
|
if (this._convertedToStream) {
|
|
throw new Error(nodbUtil.getErrorMessage('NJS-042'));
|
|
}
|
|
|
|
this._processingStarted = true;
|
|
|
|
if (numRows == 0) {
|
|
let requestedRows = this._rowCache;
|
|
|
|
const fetchArraySize = this._fetchArraySize;
|
|
while (true) { // eslint-disable-line
|
|
let rows = await this._getRows(fetchArraySize, false, false);
|
|
if (rows)
|
|
requestedRows = requestedRows.concat(rows);
|
|
if (rows.length < fetchArraySize)
|
|
break;
|
|
}
|
|
return requestedRows;
|
|
}
|
|
|
|
if (this._rowCache.length === 0) {
|
|
return await this._getRows(numRows, false, false);
|
|
}
|
|
|
|
rowsNeeded = numRows - this._rowCache.length;
|
|
if (rowsNeeded <= 0) {
|
|
return this._rowCache.splice(0, numRows);
|
|
} else {
|
|
const rows = await this._getRows(rowsNeeded, false, false);
|
|
const requestedRows = this._rowCache.concat(rows);
|
|
this._rowCache = [];
|
|
return requestedRows;
|
|
}
|
|
}
|
|
|
|
|
|
class ResultSet {
|
|
|
|
constructor() {
|
|
this._rowCache = [];
|
|
this._processingStarted = false;
|
|
this._convertedToStream = false;
|
|
this._allowGetRowCall = false;
|
|
this._isActive = false;
|
|
}
|
|
|
|
_extend(oracledb) {
|
|
this._oracledb = oracledb;
|
|
this.close = nodbUtil.callbackify(nodbUtil.preventConcurrent(nodbUtil.serialize(close), 'NJS-017'));
|
|
this.getRow = nodbUtil.callbackify(nodbUtil.preventConcurrent(nodbUtil.serialize(getRow), 'NJS-017'));
|
|
this.getRows = nodbUtil.callbackify(nodbUtil.preventConcurrent(nodbUtil.serialize(getRows), 'NJS-017'));
|
|
}
|
|
|
|
_getConnection() {
|
|
let connection = this._parentObj;
|
|
while (!(connection instanceof this._oracledb.Connection))
|
|
connection = connection._parentObj;
|
|
return connection;
|
|
}
|
|
|
|
async _getAllRows(executeOpts, metaDataObj, isNested) {
|
|
|
|
// assign result set metadata to the object; this is either a top-level
|
|
// result object that is returned to the user or a metadata object for a
|
|
// nested cursor or empty (for implicit results which don't provide
|
|
// metadata to the caller)
|
|
if (metaDataObj && !metaDataObj.metaData) {
|
|
metaDataObj.metaData = this.metaData;
|
|
}
|
|
|
|
// determine value of maxRows to use
|
|
let maxRows = this._oracledb.maxRows;
|
|
if (executeOpts && executeOpts.maxRows !== undefined) {
|
|
maxRows = executeOpts.maxRows;
|
|
}
|
|
|
|
// determine value of outFormat to use
|
|
let outFormat = this._oracledb.outFormat;
|
|
if (executeOpts && executeOpts.outFormat !== undefined) {
|
|
outFormat = executeOpts.outFormat;
|
|
}
|
|
|
|
// determine the nested cursor indices to use, allowing for both
|
|
// OUT_FORMAT_ARRAY and OUT_FORMAT_OBJECT formats
|
|
const nestedCursorMetaDataObjs = [];
|
|
const nestedCursorIndices = this._nestedCursorIndices;
|
|
for (let i = 0; i < nestedCursorIndices.length; i++) {
|
|
nestedCursorMetaDataObjs[i] =
|
|
metaDataObj.metaData[nestedCursorIndices[i]];
|
|
if (outFormat == this._oracledb.OUT_FORMAT_OBJECT) {
|
|
nestedCursorIndices[i] = nestedCursorMetaDataObjs[i].name;
|
|
}
|
|
}
|
|
|
|
// process all rows; transform nested cursors into arrays of rows by
|
|
// fetching them
|
|
let rowsFetched = [];
|
|
let fetchArraySize = this._fetchArraySize;
|
|
let closeOnFetch = false;
|
|
const closeOnAllRowsFetched = !isNested && nestedCursorIndices.length === 0;
|
|
while (true) { // eslint-disable-line
|
|
if (maxRows > 0 && fetchArraySize >= maxRows) {
|
|
fetchArraySize = maxRows;
|
|
closeOnFetch = closeOnAllRowsFetched;
|
|
}
|
|
const rows = await this._getRows(fetchArraySize, closeOnFetch,
|
|
closeOnAllRowsFetched);
|
|
if (nestedCursorIndices) {
|
|
for (let i = 0; i < rows.length; i++) {
|
|
const row = rows[i];
|
|
for (let j = 0; j < nestedCursorIndices.length; j++) {
|
|
const val = row[nestedCursorIndices[j]];
|
|
if (val) {
|
|
row[nestedCursorIndices[j]] =
|
|
await val._getAllRows(executeOpts,
|
|
nestedCursorMetaDataObjs[j], true);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (rows) {
|
|
rowsFetched = rowsFetched.concat(rows);
|
|
}
|
|
if (rows.length == maxRows || rows.length < fetchArraySize) {
|
|
break;
|
|
}
|
|
if (maxRows > 0) {
|
|
maxRows -= rows.length;
|
|
}
|
|
}
|
|
|
|
// if the cursor was not automatically closed (in order to ensure that
|
|
// nested cursors could be fetched), close it now that all rows have been
|
|
// fetched
|
|
if (!closeOnAllRowsFetched) {
|
|
await this._close();
|
|
}
|
|
return rowsFetched;
|
|
}
|
|
|
|
_getDbObjectClassJS(schema, name) {
|
|
return this._connection._getDbObjectClassJS(schema, name);
|
|
}
|
|
|
|
toQueryStream() {
|
|
nodbUtil.checkArgCount(arguments, 0, 0);
|
|
|
|
if (this._processingStarted) {
|
|
throw new Error(nodbUtil.getErrorMessage('NJS-041'));
|
|
}
|
|
|
|
if (this._convertedToStream) {
|
|
throw new Error(nodbUtil.getErrorMessage('NJS-043'));
|
|
}
|
|
|
|
this._convertedToStream = true;
|
|
|
|
return new QueryStream(this);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
module.exports = ResultSet;
|