Array row mode
Fixes https://github.com/snowflakedb/snowflake-connector-nodejs/issues/114
I added commit that bumped package.json version so we could use this fork in our project.
To get this patch to work with the execute function with a complete callback, I needed to make the following additional changes:
diff --git a/node_modules/snowflake-sdk/lib/connection/result/row_stream.js b/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
index a7f2f4a..a4d5d56 100644
--- a/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
+++ b/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
@@ -30,12 +30,13 @@ function RowStream(statement, context, options)
});
// extract streaming options
- var start, end, fetchAsString;
+ var start, end, fetchAsString, rowMode;
if (Util.isObject(options))
{
start = options.start;
end = options.end;
fetchAsString = options.fetchAsString;
+ rowMode = options.rowMode;
}
// if a fetchAsString value is not specified in the stream options, try the
@@ -49,6 +50,11 @@ function RowStream(statement, context, options)
fetchAsString = context.connectionConfig.getFetchAsString();
}
+ if (!Util.exists(rowMode))
+ {
+ rowMode = context.rowMode;
+ }
+
var resultStream = null, numResultStreamInterrupts = 0;
var rowBuffer = null, rowIndex = 0;
var columns, mapColumnIdToExtractFnName;
@@ -166,7 +172,7 @@ function RowStream(statement, context, options)
// add the next row to the read queue
process.nextTick(function ()
{
- self.push(externalizeRow(row, columns, mapColumnIdToExtractFnName));
+ self.push(externalizeRow(row, columns, mapColumnIdToExtractFnName, rowMode));
});
};
diff --git a/node_modules/snowflake-sdk/lib/connection/statement.js b/node_modules/snowflake-sdk/lib/connection/statement.js
index 98de757..933173c 100644
--- a/node_modules/snowflake-sdk/lib/connection/statement.js
+++ b/node_modules/snowflake-sdk/lib/connection/statement.js
@@ -269,6 +269,14 @@ function createContextPreExec(
JSON.stringify(fetchAsString[invalidValueIndex]));
}
+ // check for invalid arrayRowMode
+ var rowMode = statementOptions.rowMode;
+ if (Util.exists(rowMode))
+ {
+ Errors.checkArgumentValid(['array', 'object'].includes(rowMode),
+ ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE, JSON.stringify(rowMode));
+ }
+
// if parameters are specified, make sure the specified value is an object
if (Util.exists(statementOptions.parameters))
{
@@ -306,6 +314,7 @@ function createContextPreExec(
statementContext.complete = complete;
statementContext.streamResult = statementOptions.streamResult;
statementContext.fetchAsString = statementOptions.fetchAsString;
+ statementContext.rowMode = statementOptions.rowMode;
// if a binds array is specified, add it to the statement context
if (Util.exists(statementOptions.binds))
The streamRows function that gets executed in this case on line 623 of lib/connection/statement.js does not pass an options object, and so options?.rowMode is undefined within the RowStream class. Instead, we need to pull it off the statement context object instead. Looking at the code, to make this "complete", probably need to add a getRowMode and related logic to lib/connection/connection_config.js to mimic what happens with fetchAsString within the RowStream class.
For reference, the full patch we're applying against snowflake-sdk
diff --git a/node_modules/snowflake-sdk/lib/connection/connection_config.js b/node_modules/snowflake-sdk/lib/connection/connection_config.js
index cd5a5bb..793c30a 100644
--- a/node_modules/snowflake-sdk/lib/connection/connection_config.js
+++ b/node_modules/snowflake-sdk/lib/connection/connection_config.js
@@ -33,6 +33,7 @@ const DEFAULT_PARAMS =
'database',
'schema',
'role',
+ 'rowMode',
'streamResult',
'fetchAsString',
'clientSessionKeepAlive',
@@ -334,6 +335,13 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo)
JSON.stringify(fetchAsString[invalidValueIndex]));
}
+ var rowMode = options.rowMode;
+ if (Util.exists(rowMode))
+ {
+ Errors.checkArgumentValid(['array', 'object'].includes(rowMode),
+ ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE, JSON.stringify(rowMode));
+ }
+
// check for invalid clientSessionKeepAlive
var clientSessionKeepAlive = options.clientSessionKeepAlive;
if (Util.exists(clientSessionKeepAlive))
@@ -554,6 +562,16 @@ function ConnectionConfig(options, validateCredentials, qaMode, clientInfo)
return fetchAsString;
};
+ /**
+ * Returns the rowMode ('array' or 'object') string
+ *
+ * @returns {String}
+ */
+ this.getRowMode = function ()
+ {
+ return rowMode;
+ };
+
/**
* Returns the client type.
*
diff --git a/node_modules/snowflake-sdk/lib/connection/result/row_stream.js b/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
index a7f2f4a..2d76e55 100644
--- a/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
+++ b/node_modules/snowflake-sdk/lib/connection/result/row_stream.js
@@ -30,12 +30,13 @@ function RowStream(statement, context, options)
});
// extract streaming options
- var start, end, fetchAsString;
+ var start, end, fetchAsString, rowMode;
if (Util.isObject(options))
{
start = options.start;
end = options.end;
fetchAsString = options.fetchAsString;
+ rowMode = options.rowMode;
}
// if a fetchAsString value is not specified in the stream options, try the
@@ -49,6 +50,15 @@ function RowStream(statement, context, options)
fetchAsString = context.connectionConfig.getFetchAsString();
}
+ if (!Util.exists(rowMode))
+ {
+ rowMode = context.rowMode;
+ }
+ if (!Util.exists(rowMode))
+ {
+ rowMode = context.connectionConfig.getRowMode();
+ }
+
var resultStream = null, numResultStreamInterrupts = 0;
var rowBuffer = null, rowIndex = 0;
var columns, mapColumnIdToExtractFnName;
@@ -166,7 +176,7 @@ function RowStream(statement, context, options)
// add the next row to the read queue
process.nextTick(function ()
{
- self.push(externalizeRow(row, columns, mapColumnIdToExtractFnName));
+ self.push(externalizeRow(row, columns, mapColumnIdToExtractFnName, rowMode));
});
};
@@ -391,17 +401,18 @@ function buildMapColumnExtractFnNames(columns, fetchAsString)
* @param {Object} row
* @param {Object[]} columns
* @param {Object} [mapColumnIdToExtractFnName]
+ * @param {String?} rowMode - "array" or "object", defaults to "object"
*
* @returns {Object}
*/
-function externalizeRow(row, columns, mapColumnIdToExtractFnName)
+function externalizeRow(row, columns, mapColumnIdToExtractFnName, rowMode)
{
- var externalizedRow = {};
+ var externalizedRow = rowMode === "array" ? [] : {};
for (var index = 0, length = columns.length; index < length; index++)
{
var column = columns[index];
var extractFnName = mapColumnIdToExtractFnName[column.getId()];
- externalizedRow[column.getName()] = row[extractFnName](column.getId());
+ externalizedRow[rowMode === "array" ? index : column.getName()] = row[extractFnName](column.getId());
}
return externalizedRow;
diff --git a/node_modules/snowflake-sdk/lib/connection/statement.js b/node_modules/snowflake-sdk/lib/connection/statement.js
index 98de757..ff1aa75 100644
--- a/node_modules/snowflake-sdk/lib/connection/statement.js
+++ b/node_modules/snowflake-sdk/lib/connection/statement.js
@@ -161,6 +161,14 @@ exports.createStatementPostExec = function (
JSON.stringify(fetchAsString[invalidValueIndex]));
}
+ // check for invalid rowMode
+ var rowMode = statementOptions.rowMode;
+ if (Util.exists(rowMode))
+ {
+ Errors.checkArgumentValid(['array', 'object'].includes(rowMode),
+ ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE, JSON.stringify(rowMode));
+ }
+
// validate non-user-specified arguments
Errors.assertInternal(Util.isObject(services));
Errors.assertInternal(Util.isObject(connectionConfig));
@@ -172,6 +180,7 @@ exports.createStatementPostExec = function (
statementContext.complete = complete;
statementContext.streamResult = statementOptions.streamResult;
statementContext.fetchAsString = statementOptions.fetchAsString;
+ statementContext.rowMode = statementOptions.rowMode;
// set the statement type
statementContext.type = (statementContext.type == statementTypes.ROW_PRE_EXEC) ? statementTypes.ROW_POST_EXEC : statementTypes.FILE_POST_EXEC;
@@ -269,6 +278,14 @@ function createContextPreExec(
JSON.stringify(fetchAsString[invalidValueIndex]));
}
+ // check for invalid rowMode
+ var rowMode = statementOptions.rowMode;
+ if (Util.exists(rowMode))
+ {
+ Errors.checkArgumentValid(['array', 'object'].includes(rowMode),
+ ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE, JSON.stringify(rowMode));
+ }
+
// if parameters are specified, make sure the specified value is an object
if (Util.exists(statementOptions.parameters))
{
@@ -306,6 +323,7 @@ function createContextPreExec(
statementContext.complete = complete;
statementContext.streamResult = statementOptions.streamResult;
statementContext.fetchAsString = statementOptions.fetchAsString;
+ statementContext.rowMode = statementOptions.rowMode;
// if a binds array is specified, add it to the statement context
if (Util.exists(statementOptions.binds))
@@ -976,6 +994,14 @@ function createFnStreamRows(statement, context)
ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_FETCH_AS_STRING_VALUES,
JSON.stringify(fetchAsString[invalidValueIndex]));
}
+
+ // check for invalid arrayRowMode
+ var rowMode = options.rowMode;
+ if (Util.exists(rowMode))
+ {
+ Errors.checkArgumentValid(rowMode === 'array' || rowMode === 'object',
+ ErrorCodes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE, JSON.stringify(rowMode));
+ }
}
return new RowStream(statement, context, options);
diff --git a/node_modules/snowflake-sdk/lib/constants/error_messages.js b/node_modules/snowflake-sdk/lib/constants/error_messages.js
index 5a9ba0f..0a09247 100644
--- a/node_modules/snowflake-sdk/lib/constants/error_messages.js
+++ b/node_modules/snowflake-sdk/lib/constants/error_messages.js
@@ -112,6 +112,7 @@ exports[411002] = 'Invalid start index. The specified value must be a number.';
exports[411003] = 'Invalid end index. The specified value must be a number.';
exports[411004] = 'Invalid fetchAsString value. The specified value must be an Array.';
exports[411005] = 'Invalid fetchAsString type: %s. The supported types are: String, Boolean, Number, Date, and JSON.';
+exports[411006] = 'Invalid rowMode value: %s. The supported values are: "array", "object".';
exports[412001] = 'Certificate is REVOKED.';
exports[412002] = 'Certificate status is UNKNOWN.';
diff --git a/node_modules/snowflake-sdk/lib/errors.js b/node_modules/snowflake-sdk/lib/errors.js
index 4da4640..01d51f2 100644
--- a/node_modules/snowflake-sdk/lib/errors.js
+++ b/node_modules/snowflake-sdk/lib/errors.js
@@ -117,6 +117,7 @@ codes.ERR_STMT_STREAM_ROWS_INVALID_START = 411002;
codes.ERR_STMT_STREAM_ROWS_INVALID_END = 411003;
codes.ERR_STMT_STREAM_ROWS_INVALID_FETCH_AS_STRING = 411004;
codes.ERR_STMT_STREAM_ROWS_INVALID_FETCH_AS_STRING_VALUES = 411005;
+codes.ERR_STMT_STREAM_ROWS_INVALID_ROW_MODE = 411006;
// 412001
codes.ERR_OCSP_REVOKED = 412001;