dse-driver
Advanced tools
Comparing version 1.5.1 to 1.6.0
@@ -62,3 +62,4 @@ /** | ||
maxSchemaAgreementWaitSeconds: 10, | ||
maxVersion: 0 | ||
maxVersion: 0, | ||
noCompact: false | ||
}, | ||
@@ -65,0 +66,0 @@ pooling: { |
@@ -18,2 +18,4 @@ /** | ||
const ClientState = require('./metadata/client-state'); | ||
const description = require('../package.json').description; | ||
const version = require('../package.json').version; | ||
@@ -107,2 +109,12 @@ // Allow injection of the following modules | ||
* Useful for using the driver against a cluster that contains nodes with different major/minor versions of Cassandra. | ||
* @property {Boolean} protocolOptions.noCompact When set to true, enables the NO_COMPACT startup option. | ||
* <p> | ||
* When this option is supplied <code>SELECT</code>, <code>UPDATE</code>, <code>DELETE</code>, and <code>BATCH</code> | ||
* statements on <code>COMPACT STORAGE</code> tables function in "compatibility" mode which allows seeing these tables | ||
* as if they were "regular" CQL tables. | ||
* </p> | ||
* <p> | ||
* This option only effects interactions with interactions with tables using <code>COMPACT STORAGE</code> and is only | ||
* supported by C* 3.0.16+, 3.11.2+, 4.0+ and DSE 6.0+. | ||
* </p> | ||
* @property {Object} socketOptions | ||
@@ -220,8 +232,8 @@ * @property {Number} socketOptions.connectTimeout Connection timeout in milliseconds. Default: 5000. | ||
* <p>Default: <code>false</code>.</p> | ||
* @property {String} [keyspace] Specifies the keyspace for the query. Used for routing within the driver, this | ||
* property is suitable when the query operates on a different keyspace than the current {@link Client#keyspace}. | ||
* <p> | ||
* This property should only be set manually by the user when the query operates on a different keyspace than | ||
* the current {@link Client#keyspace} and using either batch or non-prepared query executions. | ||
* </p> | ||
* @property {String} [keyspace] Specifies the keyspace for the query. It is used for the following: | ||
* <ol> | ||
* <li>To indicate what keyspace the statement is applicable to (protocol V5+ only). This is useful when the | ||
* query does not provide an explicit keyspace and you want to override the current {@link Client#keyspace}.</li> | ||
* <li>For query routing when the query operates on a different keyspace than the current {@link Client#keyspace}.</li> | ||
* </ol> | ||
* @property {Boolean} [logged] Determines if the batch should be written to the batchlog. Only valid for | ||
@@ -405,2 +417,3 @@ * [Client#batch()]{@link Client#batch}, it will be ignored by other methods. Default: true. | ||
const self = this; | ||
this.log('info', util.format("Connecting to cluster using '%s' version %s", description, version)); | ||
utils.series([ | ||
@@ -683,4 +696,7 @@ function initControlConnection(next) { | ||
if (options.prepare) { | ||
// use keyspace from query options if protocol supports per-query keyspace, otherwise use connection keyspace. | ||
const version = this.controlConnection.protocolVersion; | ||
const queryKeyspace = types.protocolVersion.supportsKeyspaceInRequest(version) && options.keyspace || this.keyspace; | ||
return PrepareHandler.getPreparedMultiple( | ||
this, options.executionProfile.loadBalancing, queries, this.keyspace, function(err, result) { | ||
this, options.executionProfile.loadBalancing, queries, queryKeyspace, function(err, result) { | ||
queryItems = result; | ||
@@ -882,3 +898,5 @@ next(err); | ||
const lbp = options.executionProfile.loadBalancing; | ||
PrepareHandler.getPrepared(this, lbp, query, this.keyspace, (err, queryId, meta) => { | ||
// use keyspace from query options if protocol supports per-query keyspace, otherwise use connection keyspace. | ||
const queryKeyspace = types.protocolVersion.supportsKeyspaceInRequest(version) && options.keyspace || this.keyspace; | ||
PrepareHandler.getPrepared(this, lbp, query, queryKeyspace, (err, queryId, meta) => { | ||
if (err) { | ||
@@ -885,0 +903,0 @@ return next(err); |
@@ -27,5 +27,2 @@ /** | ||
/** @const */ | ||
const idleQuery = 'SELECT key from system.local'; | ||
/** | ||
@@ -176,3 +173,3 @@ * Represents a connection to a Cassandra node | ||
const self = this; | ||
this.sendStream(new requests.StartupRequest(), null, function responseCallback(err, response) { | ||
this.sendStream(new requests.StartupRequest(null, this.options.protocolOptions.noCompact), null, function responseCallback(err, response) { | ||
if (err && self._checkingVersion) { | ||
@@ -401,4 +398,4 @@ let invalidProtocol = (err instanceof errors.ResponseError && | ||
*/ | ||
Connection.prototype.prepareOnce = function (query, callback) { | ||
const name = ( this.keyspace || '' ) + query; | ||
Connection.prototype.prepareOnce = function (query, keyspace, callback) { | ||
const name = ( keyspace || '' ) + query; | ||
let info = this._preparing[name]; | ||
@@ -414,3 +411,3 @@ if (this._preparing[name]) { | ||
const self = this; | ||
this.sendStream(new requests.PrepareRequest(query), null, function (err, response) { | ||
this.sendStream(new requests.PrepareRequest(query, keyspace), null, function (err, response) { | ||
info.emit('prepared', err, response); | ||
@@ -505,3 +502,3 @@ delete self._preparing[name]; | ||
this.sendingIdleQuery = true; | ||
this.sendStream(new requests.QueryRequest(idleQuery), utils.emptyObject, function (err) { | ||
this.sendStream(requests.options, utils.emptyObject, function (err) { | ||
self.sendingIdleQuery = false; | ||
@@ -640,3 +637,11 @@ if (!err) { | ||
const self = this; | ||
// If server doesn't acknowledge the half-close within connection timeout, destroy the socket. | ||
const endTimeout = setTimeout(() => { | ||
this.log('info', this.endpoint + ' did not respond to connection close within ' + this.options.socketOptions.connectTimeout + 'ms, destroying connection'); | ||
this.netClient.destroy(); | ||
}, this.options.socketOptions.connectTimeout); | ||
this.netClient.once('close', function (hadError) { | ||
clearTimeout(endTimeout); | ||
if (hadError) { | ||
@@ -643,0 +648,0 @@ self.log('info', 'The socket closed with a transmission error'); |
@@ -24,3 +24,3 @@ /** | ||
const selectPeers = "SELECT peer,data_center,rack,tokens,rpc_address,release_version FROM system.peers"; | ||
const selectPeers = "SELECT * FROM system.peers"; | ||
const selectLocal = "SELECT * FROM system.local WHERE key='local'"; | ||
@@ -316,5 +316,9 @@ const newNodeDelay = 1000; | ||
if (!self.options.isMetadataSyncEnabled) { | ||
self.metadata.initialized = true; | ||
return next(); | ||
} | ||
self.metadata.refreshKeyspaces(false, next); | ||
self.metadata._refreshKeyspaces(false, true, () => { | ||
self.metadata.initialized = true; | ||
next(); | ||
}); | ||
} | ||
@@ -321,0 +325,0 @@ ], callback); |
@@ -61,4 +61,10 @@ /** | ||
this.returnType = null; | ||
/** | ||
* Indicates whether or not this aggregate is deterministic. This means that | ||
* given a particular input, the aggregate will always produce the same output. | ||
* @type {Boolean} | ||
*/ | ||
this.deterministic = null; | ||
} | ||
module.exports = Aggregate; |
@@ -155,2 +155,11 @@ /** | ||
this.clusteringOrder = []; | ||
/** | ||
* An associative Array containing nodesync options for this table. | ||
* <p> | ||
* For DSE versions prior to 6.0.0, this method always returns {@code null}. If nodesync | ||
* was not explicitly configured for this table this method will also return {@code null}. | ||
* </p> | ||
* @type {Object} | ||
*/ | ||
this.nodesync = null; | ||
} | ||
@@ -157,0 +166,0 @@ |
@@ -67,2 +67,3 @@ /** | ||
this.keyspaces = {}; | ||
this.initialized = false; | ||
this._schemaParser = schemaParserFactory.getByVersion(controlConnection, this.getUdt.bind(this)); | ||
@@ -186,2 +187,5 @@ const self = this; | ||
Metadata.prototype._refreshKeyspaceCb = function (name, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
this.log('info', util.format('Retrieving keyspace %s metadata', name)); | ||
@@ -221,4 +225,14 @@ const self = this; | ||
return this._refreshKeyspaces(waitReconnect, false, callback); | ||
}; | ||
/** | ||
* @param {Boolean} waitReconnect | ||
* @param {Boolean} internal Whether or not this was called by driver (i.e. control connection) | ||
* @param {Function} [callback] | ||
* @private | ||
*/ | ||
Metadata.prototype._refreshKeyspaces = function (waitReconnect, internal, callback) { | ||
return utils.promiseWrapper.call(this, this.options, callback, function handler(cb) { | ||
this._refreshKeyspacesCb(waitReconnect, cb); | ||
this._refreshKeyspacesCb(waitReconnect, internal, cb); | ||
}); | ||
@@ -229,6 +243,10 @@ }; | ||
* @param {Boolean} waitReconnect | ||
* @param {Boolean} internal | ||
* @param {Function} callback | ||
* @private | ||
*/ | ||
Metadata.prototype._refreshKeyspacesCb = function (waitReconnect, callback) { | ||
Metadata.prototype._refreshKeyspacesCb = function (waitReconnect, internal, callback) { | ||
if (!internal && !this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
this.log('info', 'Retrieving keyspaces metadata'); | ||
@@ -305,3 +323,3 @@ const self = this; | ||
* | ||
* @returns {Set<TokenRange>} The ranges of the ring. | ||
* @returns {Set<TokenRange>} The ranges of the ring or empty set if schema metadata is not enabled. | ||
*/ | ||
@@ -318,3 +336,3 @@ Metadata.prototype.getTokenRanges = function () { | ||
* @param {Host} host The host. | ||
* @returns {Set<TokenRange>|null} Ranges for the keyspace on this host or null if keyspace isn't found. | ||
* @returns {Set<TokenRange>|null} Ranges for the keyspace on this host or null if keyspace isn't found or hasn't been loaded. | ||
*/ | ||
@@ -420,2 +438,7 @@ Metadata.prototype.getTokenRangesForHost = function (keyspaceName, host) { | ||
/** @ignore */ | ||
Metadata.prototype._uninitializedError = function () { | ||
return new Error('Metadata has not been initialized. This could only happen if you have not connected yet.'); | ||
}; | ||
/** | ||
@@ -448,2 +471,5 @@ * Gets the definition of an user-defined type. | ||
Metadata.prototype._getUdtCb = function (keyspaceName, name, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
let cache; | ||
@@ -488,2 +514,5 @@ if (this.options.isMetadataSyncEnabled) { | ||
Metadata.prototype._getTableCb = function (keyspaceName, name, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
let cache; | ||
@@ -657,2 +686,5 @@ if (this.options.isMetadataSyncEnabled) { | ||
Metadata.prototype._getMaterializedViewCb = function (keyspaceName, name, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
let cache; | ||
@@ -678,2 +710,5 @@ if (this.options.isMetadataSyncEnabled) { | ||
Metadata.prototype._getFunctions = function (keyspaceName, name, aggregate, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
let cache; | ||
@@ -765,2 +800,5 @@ if (this.options.isMetadataSyncEnabled) { | ||
Metadata.prototype._getTraceCb = function (traceId, consistency, callback) { | ||
if (!this.initialized) { | ||
return callback(this._uninitializedError(), null); | ||
} | ||
let trace; | ||
@@ -767,0 +805,0 @@ let attempts = 0; |
@@ -60,4 +60,30 @@ /** | ||
this.returnType = null; | ||
/** | ||
* Indicates whether or not this function is deterministic. This means that | ||
* given a particular input, the function will always produce the same output. | ||
* @type {Boolean} | ||
*/ | ||
this.deterministic = null; | ||
/** | ||
* Indicates whether or not this function is monotonic on all of its | ||
* arguments. This means that it is either entirely non-increasing or | ||
* non-decreasing. Even if the function is not monotonic on all of its | ||
* arguments, it's possible to specify that it is monotonic on one of | ||
* its arguments, meaning that partial applications of the function over | ||
* that argument will be monotonic. | ||
* | ||
* Monotonicity is required to use the function in a GROUP BY clause. | ||
* @type {Boolean} | ||
*/ | ||
this.monotonic = null; | ||
/** | ||
* The argument names that the function is monotonic on. | ||
* | ||
* If {@link monotonic} is true, this will return all argument names. | ||
* Otherwise, this will return either one argument or an empty array. | ||
* @type {Array.<String>} | ||
*/ | ||
this.monotonicOn = null; | ||
} | ||
module.exports = SchemaFunction; |
@@ -776,2 +776,3 @@ /** | ||
tableInfo.maxIndexInterval = tableRow['max_index_interval'] || tableInfo.maxIndexInterval; | ||
tableInfo.nodesync = tableRow['nodesync'] || tableInfo.nodesync; | ||
if (!isView) { | ||
@@ -859,2 +860,3 @@ const cdc = tableRow['cdc']; | ||
aggregate.initCondition = aggregate.initConditionRaw; | ||
aggregate.deterministic = row['deterministic'] || false; | ||
const self = this; | ||
@@ -901,2 +903,5 @@ utils.series([ | ||
func.language = row['language']; | ||
func.deterministic = row['deterministic'] || false; | ||
func.monotonic = row['monotonic'] || false; | ||
func.monotonicOn = row['monotonic_on'] || utils.emptyArray; | ||
const self = this; | ||
@@ -903,0 +908,0 @@ utils.series([ |
@@ -127,3 +127,3 @@ /** | ||
} | ||
connection.prepareOnce(query, function prepareOnceCallback(err, response) { | ||
connection.prepareOnce(query, keyspace, function prepareOnceCallback(err, response) { | ||
if (err) { | ||
@@ -202,3 +202,3 @@ return self._onPrepareError(err, host, triedHosts, info, iterator, query, keyspace); | ||
utils.each(queries, function prepareEach(query, next) { | ||
connection.prepareOnce(query, next); | ||
connection.prepareOnce(query, keyspace, next); | ||
}, callback); | ||
@@ -229,3 +229,3 @@ }); | ||
} | ||
connection.prepareOnce(query, function (err) { | ||
connection.prepareOnce(query, keyspace, function (err) { | ||
if (err) { | ||
@@ -232,0 +232,0 @@ // There has been error |
@@ -21,2 +21,3 @@ /** | ||
noMetadata: 0x0004, | ||
metadataChanged: 0x0008, | ||
continuousPaging: 0x40000000, | ||
@@ -287,2 +288,7 @@ lastContinuousPage: 0x80000000, | ||
const meta = {}; | ||
if (types.protocolVersion.supportsResultMetadataId(this.header.version) && isPrepared) { | ||
meta.resultId = utils.copyBuffer(this.readShortBytes()); | ||
} | ||
//as used in Rows and Prepared responses | ||
@@ -302,2 +308,5 @@ const flags = this.readInt(); | ||
} | ||
if (flags & resultFlag.metadataChanged) { | ||
meta.newResultId = utils.copyBuffer(this.readShortBytes()); | ||
} | ||
if (flags & resultFlag.continuousPaging) { | ||
@@ -304,0 +313,0 @@ meta.continuousPageIndex = this.readInt(); |
@@ -66,6 +66,5 @@ /** | ||
_sendOnConnection() { | ||
const self = this; | ||
this._operation = | ||
this._connection.sendStream(this._request, this._parent.requestOptions, function responseCb(err, response) { | ||
if (self._cancelled) { | ||
this._connection.sendStream(this._request, this._parent.requestOptions, (err, response) => { | ||
if (this._cancelled) { | ||
// Avoid handling the response / err | ||
@@ -75,19 +74,25 @@ return; | ||
if (err) { | ||
return self._handleError(err); | ||
return this._handleError(err); | ||
} | ||
const result = self._getResultSet(response); | ||
const result = this._getResultSet(response); | ||
if (response.schemaChange) { | ||
return self._parent.client.handleSchemaAgreementAndRefresh( | ||
self._connection, response.schemaChange, function schemaCb(){ | ||
if (self._cancelled) { | ||
return this._parent.client.handleSchemaAgreementAndRefresh( | ||
this._connection, response.schemaChange, () => { | ||
if (this._cancelled) { | ||
// After the schema agreement method was started, this execution was cancelled | ||
return; | ||
} | ||
self._parent.setCompleted(null, result); | ||
this._parent.setCompleted(null, result); | ||
}); | ||
} | ||
if (response.keyspaceSet) { | ||
self._parent.client.keyspace = response.keyspaceSet; | ||
this._parent.client.keyspace = response.keyspaceSet; | ||
} | ||
self._parent.setCompleted(null, result); | ||
if (response.meta && response.meta.newResultId && this._request.queryId) { | ||
// Update the resultId on the existing prepared statement. | ||
// Eventually would want to update the result metadata as well (NODEJS-433) | ||
const info = this._parent.client.metadata.getPreparedById(this._request.queryId); | ||
info.meta.resultId = response.meta.newResultId; | ||
} | ||
this._parent.setCompleted(null, result); | ||
}); | ||
@@ -199,3 +204,3 @@ } | ||
*/ | ||
_retry(consistency, useCurrentHost) { | ||
_retry(consistency, useCurrentHost, meta) { | ||
if (this._cancelled) { | ||
@@ -207,5 +212,12 @@ // No point in retrying | ||
this._retryCount++; | ||
if (typeof consistency === 'number' && this._request.consistency !== consistency) { | ||
if (meta || (typeof consistency === 'number' && this._request.consistency !== consistency)) { | ||
this._request = this._request.clone(); | ||
this._request.consistency = consistency; | ||
if (typeof consistency === 'number') { | ||
this._request.consistency = consistency; | ||
} | ||
// possible that we are retrying because we had to reprepare. In this case it is also possible | ||
// that our known metadata had changed, therefore we update it on the request. | ||
if (meta) { | ||
this._request.meta = meta; | ||
} | ||
} | ||
@@ -236,3 +248,4 @@ if (useCurrentHost !== false) { | ||
} | ||
if (info.keyspace && info.keyspace !== this._connection.keyspace) { | ||
const version = this._connection.protocolVersion; | ||
if (!types.protocolVersion.supportsKeyspaceInRequest(version) && info.keyspace && info.keyspace !== this._connection.keyspace) { | ||
return this._parent.setCompleted( | ||
@@ -243,3 +256,3 @@ new Error(util.format('Query was prepared on keyspace %s, can\'t execute it on %s (%s)', | ||
const self = this; | ||
this._connection.prepareOnce(info.query, function (err) { | ||
this._connection.prepareOnce(info.query, info.keyspace, function (err, result) { | ||
if (err) { | ||
@@ -253,3 +266,7 @@ if (!err.isSocketError && err instanceof errors.OperationTimedOutError) { | ||
} | ||
self._retry(undefined, true); | ||
// possible that when repreparing we got new metadata (i.e. if schema changed), update cache. | ||
info.meta = result.meta; | ||
// pass the metadata so it can be used in retry. | ||
self._retry(undefined, true, result.meta); | ||
}); | ||
@@ -256,0 +273,0 @@ } |
@@ -27,2 +27,3 @@ /** | ||
withNameForValues: 0x40, | ||
withKeyspace: 0x80, | ||
withPageSizeBytes: 0x40000000, | ||
@@ -33,3 +34,3 @@ withContinuousPaging: 0x80000000 | ||
/** | ||
* Options for the executing of a batch request from protocol v3 and above | ||
* Options for the execution of a batch request from protocol v3 and above | ||
* @private | ||
@@ -40,6 +41,15 @@ */ | ||
withDefaultTimestamp: 0x20, | ||
withNameForValues: 0x40 | ||
withNameForValues: 0x40, | ||
withKeyspace: 0x80 | ||
}; | ||
/** | ||
* Options for execution of a prepare request from protocol DSE_V2 and above | ||
* @private | ||
*/ | ||
const prepareFlag = { | ||
withKeyspace: 0x01 | ||
}; | ||
/** | ||
* Abstract class Request | ||
@@ -119,2 +129,5 @@ */ | ||
frameWriter.writeShortBytes(this.queryId); | ||
if(types.protocolVersion.supportsResultMetadataId(encoder.protocolVersion)) { | ||
frameWriter.writeShortBytes(this.meta.resultId); | ||
} | ||
this.writeQueryParameters(frameWriter, encoder); | ||
@@ -128,4 +141,5 @@ return frameWriter.write(encoder.protocolVersion, streamId, headerFlags); | ||
* @param {Encoder} encoder | ||
* @param {Boolean} [isQuery] True if query, otherwise assumed to be execute request. | ||
*/ | ||
writeQueryParameters(frameWriter, encoder) { | ||
writeQueryParameters(frameWriter, encoder, isQuery) { | ||
//v1: <n><value_1>....<value_n><consistency> | ||
@@ -136,2 +150,4 @@ //v2: <consistency><flags>[<n><value_1>...<value_n>][<result_page_size>][<paging_state>][<serial_consistency>] | ||
// [<serial_consistency>][<timestamp>][continuous_paging_options] | ||
//dse_v2: <consistency><flags>[<n>[name_1]<value_1>...[name_n]<value_n>][<result_page_size>][<paging_state>] | ||
// [<serial_consistency>][<timestamp>][keyspace][continuous_paging_options] | ||
let flags = 0; | ||
@@ -145,2 +161,4 @@ if (types.protocolVersion.supportsPaging(encoder.protocolVersion)) { | ||
flags |= this.namedParameters ? queryFlag.withNameForValues : 0; | ||
// Don't inject keyspace for EXECUTE requests as inherited from prepared statement. | ||
flags |= isQuery && this.options.keyspace && types.protocolVersion.supportsKeyspaceInRequest(encoder.protocolVersion) ? queryFlag.withKeyspace : 0; | ||
frameWriter.writeShort(this.consistency); | ||
@@ -199,2 +217,5 @@ if (types.protocolVersion.uses4BytesQueryFlags(encoder.protocolVersion)) { | ||
} | ||
if (flags & queryFlag.withKeyspace) { | ||
frameWriter.writeString(this.options.keyspace); | ||
} | ||
if (flags & queryFlag.withContinuousPaging) { | ||
@@ -237,3 +258,3 @@ frameWriter.writeInt(this.options.continuousPaging.maxPages || 0); | ||
//Use the same fields as the execute writer | ||
this.writeQueryParameters(frameWriter, encoder); | ||
this.writeQueryParameters(frameWriter, encoder, true); | ||
} | ||
@@ -245,5 +266,6 @@ return frameWriter.write(encoder.protocolVersion, streamId, headerFlags); | ||
class PrepareRequest extends Request { | ||
constructor(query) { | ||
constructor(query, keyspace) { | ||
super(); | ||
this.query = query; | ||
this.keyspace = keyspace; | ||
} | ||
@@ -254,2 +276,9 @@ | ||
frameWriter.writeLString(this.query); | ||
if (types.protocolVersion.supportsPrepareFlags(encoder.protocolVersion)) { | ||
const flags = this.keyspace && types.protocolVersion.supportsKeyspaceInRequest(encoder.protocolVersion) ? prepareFlag.withKeyspace : 0; | ||
frameWriter.writeInt(flags); | ||
if (flags & prepareFlag.withKeyspace) { | ||
frameWriter.writeString(this.keyspace); | ||
} | ||
} | ||
return frameWriter.write(encoder.protocolVersion, streamId); | ||
@@ -259,5 +288,6 @@ } | ||
class StartupRequest extends Request { | ||
constructor(cqlVersion) { | ||
constructor(cqlVersion, noCompact) { | ||
super(); | ||
this.cqlVersion = cqlVersion || '3.0.0'; | ||
this.noCompact = noCompact; | ||
} | ||
@@ -267,5 +297,9 @@ | ||
const frameWriter = new FrameWriter(types.opcodes.startup); | ||
frameWriter.writeStringMap({ | ||
const startupOptions = { | ||
CQL_VERSION: this.cqlVersion | ||
}); | ||
}; | ||
if(this.noCompact) { | ||
startupOptions['NO_COMPACT'] = 'true'; | ||
} | ||
frameWriter.writeStringMap(startupOptions); | ||
return frameWriter.write(encoder.protocolVersion, streamId); | ||
@@ -344,3 +378,3 @@ } | ||
//v3: <type><n><query_1>...<query_n><consistency><flags>[<serial_consistency>][<timestamp>] | ||
//dseV1: similar to v3/v4, flags is an int instead of a byte | ||
//dseV1+: similar to v3/v4, flags is an int instead of a byte | ||
if (!this.queries || !(this.queries.length > 0)) { | ||
@@ -385,2 +419,3 @@ throw new TypeError(util.format('Invalid queries provided %s', this.queries)); | ||
flags |= this.options.timestamp ? batchFlag.withDefaultTimestamp : 0; | ||
flags |= this.options.keyspace && types.protocolVersion.supportsKeyspaceInRequest(encoder.protocolVersion) ? batchFlag.withKeyspace : 0; | ||
if (types.protocolVersion.uses4BytesQueryFlags(encoder.protocolVersion)) { | ||
@@ -402,2 +437,5 @@ frameWriter.writeInt(flags); | ||
} | ||
if (flags & batchFlag.withKeyspace) { | ||
frameWriter.writeString(this.options.keyspace); | ||
} | ||
} | ||
@@ -426,2 +464,17 @@ return frameWriter.write(encoder.protocolVersion, streamId, headerFlags); | ||
class OptionsRequest extends Request { | ||
write(encoder, streamId) { | ||
const frameWriter = new FrameWriter(types.opcodes.options); | ||
return frameWriter.write(encoder.protocolVersion, streamId, 0); | ||
} | ||
clone() { | ||
// since options has no unique state, simply return self. | ||
return this; | ||
} | ||
} | ||
const options = new OptionsRequest(); | ||
exports.AuthResponseRequest = AuthResponseRequest; | ||
@@ -436,2 +489,3 @@ exports.BatchRequest = BatchRequest; | ||
exports.RegisterRequest = RegisterRequest; | ||
exports.StartupRequest = StartupRequest; | ||
exports.StartupRequest = StartupRequest; | ||
exports.options = options; |
@@ -245,2 +245,21 @@ /** | ||
* Server error codes returned by Cassandra | ||
* @type {Object} | ||
* @property {Number} serverError Something unexpected happened. | ||
* @property {Number} protocolError Some client message triggered a protocol violation. | ||
* @property {Number} badCredentials Authentication was required and failed. | ||
* @property {Number} unavailableException Raised when coordinator knows there is not enough replicas alive to perform a query with the requested consistency level. | ||
* @property {Number} overloaded The request cannot be processed because the coordinator is overloaded. | ||
* @property {Number} isBootstrapping The request was a read request but the coordinator node is bootstrapping. | ||
* @property {Number} truncateError Error encountered during a truncate request. | ||
* @property {Number} writeTimeout Timeout encountered on write query on coordinator waiting for response(s) from replicas. | ||
* @property {Number} readTimeout Timeout encountered on read query on coordinator waitign for response(s) from replicas. | ||
* @property {Number} readFailure A non-timeout error encountered during a read request. | ||
* @property {Number} functionFailure A (user defined) function encountered during execution. | ||
* @property {Number} writeFailure A non-timeout error encountered during a write request. | ||
* @property {Number} syntaxError The submitted query has a syntax error. | ||
* @property {Number} unauthorized The logged user doesn't have the right to perform the query. | ||
* @property {Number} invalid The query is syntactically correct but invalid. | ||
* @property {Number} configError The query is invalid because of some configuration issue. | ||
* @property {Number} alreadyExists The query attempted to create a schema element (i.e. keyspace, table) that already exists. | ||
* @property {Number} unprepared Can be thrown while a prepared statement tries to be executed if the provided statement is not known by the coordinator. | ||
*/ | ||
@@ -247,0 +266,0 @@ const responseErrorCodes = { |
@@ -16,2 +16,3 @@ /** | ||
const v510 = VersionNumber.parse('5.1.0'); | ||
const v600 = VersionNumber.parse('6.0.0'); | ||
@@ -28,2 +29,3 @@ /** | ||
* @property {Number} dseV1 DataStax Enterprise protocol v1, DSE 5.1+ | ||
* @property {Number} dseV2 DataStax Enterprise protocol v2, DSE 6.0+ | ||
* @property {Number} maxSupported Returns the higher protocol version that is supported by this driver. | ||
@@ -44,8 +46,53 @@ * @property {Number} minSupported Returns the lower protocol version that is supported by this driver. | ||
dseV1: 0x41, | ||
maxSupported: 0x41, | ||
dseV2: 0x42, | ||
maxSupported: 0x42, | ||
minSupported: 0x01, | ||
/** | ||
* Determines whether the protocol version is a DSE-specific protocol version. | ||
* @param {Number} version | ||
* @returns {Boolean} | ||
* @ignore | ||
*/ | ||
isDse: function(version) { | ||
return ((version >= this.dseV1 && version <= this.dseV2)); | ||
}, | ||
/** | ||
* Determines whether the protocol protocol version is supported by this driver. | ||
* @param {Number} version | ||
* @returns {Boolean} | ||
* @ignore | ||
*/ | ||
isSupported: function (version) { | ||
return (version === this.dseV1 || (version <= 0x04 && version >= 0x01)); | ||
return (this.isDse(version) || (version <= 0x04 && version >= 0x01)); | ||
}, | ||
/** | ||
* Determines whether the protocol includes flags for PREPARE messages. | ||
* @param {Number} version | ||
* @returns {Boolean} | ||
* @ignore | ||
*/ | ||
supportsPrepareFlags: function (version) { | ||
return (version === this.dseV2); | ||
}, | ||
/** | ||
* Determines whether the protocol supports sending the keyspace as part of PREPARE, QUERY, EXECUTE, and BATCH. | ||
* @param {Number} version | ||
* @returns {Boolean} | ||
* @ignore | ||
*/ | ||
supportsKeyspaceInRequest: function (version) { | ||
return (version === this.dseV2); | ||
}, | ||
/** | ||
* Determines whether the protocol supports result_metadata_id on `prepared` response and | ||
* and `execute` request. | ||
* @param {Number} version | ||
* @returns {Boolean} | ||
* @ignore | ||
*/ | ||
supportsResultMetadataId: function (version) { | ||
return (version === this.dseV2); | ||
}, | ||
/** | ||
* Determines whether the protocol supports partition key indexes in the `prepared` RESULT responses. | ||
@@ -76,3 +123,3 @@ * @param {Number} version | ||
supportsContinuousPaging: function (version) { | ||
return (version === this.dseV1); | ||
return (this.isDse(version)); | ||
}, | ||
@@ -150,3 +197,3 @@ /** | ||
uses4BytesQueryFlags: function (version) { | ||
return (version === this.dseV1); | ||
return (this.isDse(version)); | ||
}, | ||
@@ -210,3 +257,7 @@ /** | ||
v3Requirement = true; | ||
maxVersion = Math.min(this.dseV1, maxVersion); | ||
if (dseVersion.compare(v600) >= 0) { | ||
maxVersion = Math.min(this.dseV2, maxVersion); | ||
} else { | ||
maxVersion = Math.min(this.dseV1, maxVersion); | ||
} | ||
maxVersionWith3OrMore = maxVersion; | ||
@@ -213,0 +264,0 @@ return; |
@@ -180,5 +180,5 @@ /** | ||
const timeHigh = val.getHighBitsUnsigned(); | ||
buffer.writeUInt32BE(val.getLowBitsUnsigned(), 0, true); | ||
buffer.writeUInt16BE(timeHigh & 0xffff, 4, true); | ||
buffer.writeUInt16BE(timeHigh >>> 16 & 0xffff, 6, true); | ||
buffer.writeUInt32BE(val.getLowBitsUnsigned(), 0); | ||
buffer.writeUInt16BE(timeHigh & 0xffff, 4); | ||
buffer.writeUInt16BE(timeHigh >>> 16 & 0xffff, 6); | ||
} | ||
@@ -185,0 +185,0 @@ |
{ | ||
"name": "dse-driver", | ||
"version": "1.5.1", | ||
"version": "1.6.0", | ||
"description": "DataStax Enterprise Node.js Driver", | ||
@@ -5,0 +5,0 @@ "author": "DataStax", |
Sorry, the diff of this file is not supported yet
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
747599
21621
79
7