Estructura inicial del proyecto

This commit is contained in:
2026-06-02 16:57:08 +00:00
commit 8b306b9afc
9864 changed files with 1435687 additions and 0 deletions

22
backend/node_modules/mssql/LICENSE.md generated vendored Normal file
View File

@ -0,0 +1,22 @@
MIT License
Copyright (c) 2013-2018 Patrik Simek and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2419
backend/node_modules/mssql/README.md generated vendored Normal file

File diff suppressed because it is too large Load Diff

133
backend/node_modules/mssql/bin/mssql generated vendored Executable file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env node
const { Command } = require('commander')
const { version } = require('../package.json')
const { resolve: resolvePath } = require('node:path')
const { constants: { R_OK } } = require('node:fs')
const { ConnectionPool } = require('../')
const { lstat, access, readFile } = require('node:fs/promises')
Buffer.prototype.toJSON = () => {
return `0x${this.toString('hex')}`
}
/**
* @param {Readable} stream
* @returns {Promise<Buffer>}
*/
async function streamToBuffer (stream) {
const chunks = []
return new Promise((resolve, reject) => {
stream.on('data', (chunk) => {
chunks.push(chunk)
})
stream.on('end', () => {
resolve(Buffer.concat(chunks))
})
stream.on('error', reject)
})
}
async function resolveConfig (opts, cfgFile) {
const cfg = Object.entries({
options: {
encrypt: opts.encrypt,
trustServerCertificate: opts.trustServerCertificate,
tdsVersion: opts.tdsVersion
},
user: opts.user,
password: opts.password,
server: opts.server,
database: opts.database,
port: opts.port
}).reduce((config, [key, value]) => {
if (value) {
Object.assign(config, {
[key]: value
})
}
return config
}, {})
let cfgPath = cfgFile || process.cwd()
const stat = await lstat(resolvePath(cfgPath))
if (stat.isDirectory()) {
cfgPath = resolvePath(cfgPath, opts.config)
}
const configAccess = await access(cfgPath, R_OK).then(() => true).catch(() => false)
if (!configAccess) {
return cfg;
}
const config = await (readFile(cfgPath))
.then((content) => JSON.parse(content.toString()))
return {
...config,
...cfg,
options: {
...(config.options || {}),
...cfg.options
}
}
}
const program = new Command()
program
.name('mssql')
.argument('[configPath]')
.description('CLI tools for node-mssql')
.version(version)
.option('--config <file>', 'Configuration file for the connection', './.mssql.json')
.option('--user <user>', 'User for the database connection')
.option('--password <password>', 'Password for the database connection')
.option('--server <server>', 'Server for the database connection')
.option('--database <database>', 'Database for the database connection')
.option('--tds-version <version>', 'TDS version to use for the database connection')
.option('--port <port>', 'Port for the database connection', parseInt)
.option('--encrypt', 'Use the encrypt option for this connection', false)
.option('--trust-server-certificate', 'Trust the server certificate for this connection', false)
// .option('--format <format>', 'The output format to use, eg: JSON', 'json')
.action(async function (configPath, opts) {
const [config, statement] = await Promise.all([
resolveConfig(opts, configPath),
streamToBuffer(process.stdin).then((stmt) => stmt.toString().trim())
])
if (!statement.length) {
throw new Error('Statement is empty.')
}
const pool = await (new ConnectionPool(config)).connect()
const request = pool.request()
request.stream = true
let started = false
request.on('error', (e) => {
pool.close()
throw e
})
request.on('recordset', () => {
if (started) {
process.stdout.write('],')
} else {
process.stdout.write('[')
}
started = false
})
request.on('row', (row) => {
if (!started) {
started = true
process.stdout.write('[')
} else {
process.stdout.write(',')
}
process.stdout.write(JSON.stringify(row))
})
request.on('done', () => {
if (started) {
process.stdout.write(']]')
}
process.stdout.write('\n')
pool.close()
})
request.query(statement)
})
program.parseAsync(process.argv).catch((e) => {
program.error(e.message, { exitCode: 1 });
})

3
backend/node_modules/mssql/index.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
'use strict'
module.exports = require('./lib/tedious')

712
backend/node_modules/mssql/lib/base/connection-pool.js generated vendored Normal file
View File

@ -0,0 +1,712 @@
'use strict'
const { EventEmitter } = require('node:events')
const debug = require('debug')('mssql:base')
const { parse, MSSQL_SCHEMA } = require('@tediousjs/connection-string')
const tarn = require('tarn')
const { IDS } = require('../utils')
const ConnectionError = require('../error/connection-error')
const shared = require('../shared')
const { MSSQLError } = require('../error')
const { CHANNELS, tracePromise, traceCallback, publish } = require('../diagnostics')
const NODE_MSSQL_SCHEMA = {
...MSSQL_SCHEMA,
useutc: { type: 'boolean' },
stream: { type: 'boolean' },
parsejson: { type: 'boolean' },
'request timeout': { type: 'number' }
}
/**
* Class ConnectionPool.
*
* Internally, each `Connection` instance is a separate pool of TDS connections. Once you create a new `Request`/`Transaction`/`Prepared Statement`, a new TDS connection is acquired from the pool and reserved for desired action. Once the action is complete, connection is released back to the pool.
*
* @property {Boolean} connected If true, connection is established.
* @property {Boolean} connecting If true, connection is being established.
*
* @fires ConnectionPool#connect
* @fires ConnectionPool#close
*/
class ConnectionPool extends EventEmitter {
/**
* Create new Connection.
*
* @param {Object|String} config Connection configuration object or connection string.
* @param {basicCallback} [callback] A callback which is called after connection has established, or an error has occurred.
*/
constructor (config, callback) {
super()
IDS.add(this, 'ConnectionPool')
debug('pool(%d): created', IDS.get(this))
this._connectStack = []
this._closeStack = []
this._connected = false
this._connecting = false
this._healthy = false
if (typeof config === 'string') {
try {
this.config = this.constructor.parseConnectionString(config)
} catch (ex) {
if (typeof callback === 'function') {
return setImmediate(callback, ex)
}
throw ex
}
} else {
this.config = config
}
// set defaults
this.config.port = this.config.port || 1433
this.config.options = this.config.options || {}
this.config.stream = this.config.stream || false
this.config.parseJSON = this.config.parseJSON || false
this.config.arrayRowMode = this.config.arrayRowMode || false
this.config.validateConnection = 'validateConnection' in this.config ? this.config.validateConnection : true
const namedServer = /^(.*)\\(.*)$/.exec(this.config.server)
if (namedServer) {
this.config.server = namedServer[1]
this.config.options.instanceName = namedServer[2]
}
if (typeof this.config.options.useColumnNames !== 'undefined' && this.config.options.useColumnNames !== true) {
const ex = new MSSQLError('Invalid options `useColumnNames`, use `arrayRowMode` instead')
if (typeof callback === 'function') {
return setImmediate(callback, ex)
}
throw ex
}
if (typeof callback === 'function') {
this.connect(callback)
}
}
get connected () {
return this._connected
}
get connecting () {
return this._connecting
}
get healthy () {
return this._healthy
}
static parseConnectionString (connectionString) {
return this._parseConnectionString(connectionString)
}
static _parseAuthenticationType (type, entries) {
if (!type) return 'default'
switch (type.toLowerCase()) {
case 'active directory integrated':
if (entries.includes('token')) {
return 'azure-active-directory-access-token'
} else if (['client id', 'client secret', 'tenant id'].every(entry => entries.includes(entry))) {
return 'azure-active-directory-service-principal-secret'
} else if (['client id', 'msi endpoint', 'msi secret'].every(entry => entries.includes(entry))) {
return 'azure-active-directory-msi-app-service'
} else if (['client id', 'msi endpoint'].every(entry => entries.includes(entry))) {
return 'azure-active-directory-msi-vm'
}
return 'azure-active-directory-default'
case 'active directory password':
return 'azure-active-directory-password'
case 'ntlm':
return 'ntlm'
default:
return 'default'
}
}
static _parseConnectionString (connectionString) {
const result = parse(connectionString)
const parsed = result.toSchema(NODE_MSSQL_SCHEMA)
// Include non-standard keys (client id, tenant id, token, msi endpoint, msi secret)
// that are used for authentication but not part of the MSSQL schema
for (const [key, value] of result) {
if (!(key in parsed)) {
parsed[key] = value
}
}
return Object.entries(parsed).reduce((config, [key, value]) => {
switch (key) {
case 'application name':
break
case 'applicationintent':
Object.assign(config.options, {
readOnlyIntent: value === 'readonly'
})
break
case 'asynchronous processing':
break
case 'attachdbfilename':
break
case 'authentication':
Object.assign(config, {
authentication_type: this._parseAuthenticationType(value, Object.keys(parsed))
})
break
case 'column encryption setting':
break
case 'connection timeout':
Object.assign(config, {
connectionTimeout: value * 1000
})
break
case 'connection lifetime':
break
case 'connectretrycount':
break
case 'connectretryinterval':
Object.assign(config.options, {
connectionRetryInterval: value * 1000
})
break
case 'context connection':
break
case 'client id':
Object.assign(config, {
clientId: value
})
break
case 'client secret':
Object.assign(config, {
clientSecret: value
})
break
case 'current language':
Object.assign(config.options, {
language: value
})
break
case 'data source':
{
let server = value
let instanceName
let port = 1433
if (/^np:/i.test(server)) {
throw new Error('Connection via Named Pipes is not supported.')
}
if (/^tcp:/i.test(server)) {
server = server.substr(4)
}
const namedServerParts = /^(.*)\\(.*)$/.exec(server)
if (namedServerParts) {
server = namedServerParts[1].trim()
instanceName = namedServerParts[2].trim()
}
const serverParts = /^(.*),(.*)$/.exec(server)
if (serverParts) {
server = serverParts[1].trim()
port = parseInt(serverParts[2].trim(), 10)
} else {
const instanceParts = /^(.*),(.*)$/.exec(instanceName)
if (instanceParts) {
instanceName = instanceParts[1].trim()
port = parseInt(instanceParts[2].trim(), 10)
}
}
if (server === '.' || server === '(.)' || server.toLowerCase() === '(localdb)' || server.toLowerCase() === '(local)') {
server = 'localhost'
}
Object.assign(config, {
port,
server
})
if (instanceName) {
Object.assign(config.options, {
instanceName
})
}
break
}
case 'encrypt':
Object.assign(config.options, {
encrypt: !!value
})
break
case 'enlist':
break
case 'failover partner':
break
case 'initial catalog':
Object.assign(config, {
database: value
})
break
case 'integrated security':
break
case 'max pool size':
Object.assign(config.pool, {
max: value
})
break
case 'min pool size':
Object.assign(config.pool, {
min: value
})
break
case 'msi endpoint':
Object.assign(config, {
msiEndpoint: value
})
break
case 'msi secret':
Object.assign(config, {
msiSecret: value
})
break
case 'multipleactiveresultsets':
break
case 'multisubnetfailover':
Object.assign(config.options, {
multiSubnetFailover: value
})
break
case 'network library':
break
case 'packet size':
Object.assign(config.options, {
packetSize: value
})
break
case 'password':
Object.assign(config, {
password: value
})
break
case 'persist security info':
break
case 'poolblockingperiod':
break
case 'pooling':
break
case 'replication':
break
case 'tenant id':
Object.assign(config, {
tenantId: value
})
break
case 'token':
Object.assign(config, {
token: value
})
break
case 'transaction binding':
Object.assign(config.options, {
enableImplicitTransactions: value.toLowerCase() === 'implicit unbind'
})
break
case 'transparentnetworkipresolution':
break
case 'trustservercertificate':
Object.assign(config.options, {
trustServerCertificate: value
})
break
case 'type system version':
break
case 'user id': {
let user = value
let domain
const domainUser = /^(.*)\\(.*)$/.exec(user)
if (domainUser) {
domain = domainUser[1]
user = domainUser[2]
}
if (domain) {
Object.assign(config, {
domain
})
}
if (user) {
Object.assign(config, {
user
})
}
break
}
case 'user instance':
break
case 'workstation id':
Object.assign(config.options, {
workstationId: value
})
break
case 'request timeout':
Object.assign(config, {
requestTimeout: parseInt(value, 10)
})
break
case 'stream':
Object.assign(config, {
stream: !!value
})
break
case 'useutc':
Object.assign(config.options, {
useUTC: !!value
})
break
case 'parsejson':
Object.assign(config, {
parseJSON: !!value
})
break
}
return config
}, { options: {}, pool: {} })
}
/**
* Acquire connection from this connection pool.
*
* @param {ConnectionPool|Transaction|PreparedStatement} requester Requester.
* @param {acquireCallback} [callback] A callback which is called after connection has been acquired, or an error has occurred. If omited, method returns Promise.
* @return {ConnectionPool|Promise}
*/
acquire (requester, callback) {
const requestId = IDS.get(requester)
const poolId = IDS.get(this)
const acquirePromise = tracePromise(CHANNELS.TRACE_POOL_ACQUIRE, () => {
return shared.Promise.resolve(this._acquire()).catch(err => {
this.emit('error', err)
throw err
}).then(connection => {
publish(CHANNELS.CONNECTION_ACQUIRE, () => ({
connectionId: IDS.get(connection),
requestId,
poolId
}))
return connection
})
}, () => ({
poolId,
requestId
}))
if (typeof callback === 'function') {
acquirePromise.then(connection => callback(null, connection, this.config)).catch(callback)
return this
}
return acquirePromise
}
_acquire () {
if (!this.pool) {
return shared.Promise.reject(new ConnectionError('Connection not yet open.', 'ENOTOPEN'))
} else if (this.pool.destroyed) {
return shared.Promise.reject(new ConnectionError('Connection is closing', 'ENOTOPEN'))
}
return this.pool.acquire().promise
}
/**
* Release connection back to the pool.
*
* @param {Connection} connection Previously acquired connection.
* @return {ConnectionPool}
*/
release (connection) {
debug('connection(%d): released', IDS.get(connection))
publish(CHANNELS.CONNECTION_RELEASE, () => ({
connectionId: IDS.get(connection),
poolId: IDS.get(this)
}))
if (this.pool) {
this.pool.release(connection)
}
return this
}
/**
* Creates a new connection pool with one active connection. This one initial connection serves as a probe to find out whether the configuration is valid.
*
* @param {basicCallback} [callback] A callback which is called after connection has established, or an error has occurred. If omited, method returns Promise.
* @return {ConnectionPool|Promise}
*/
connect (callback) {
if (typeof callback === 'function') {
traceCallback(CHANNELS.TRACE_CONNECT, this._connect, 0, () => ({
server: this.config.server,
port: this.config.port,
database: this.config.database,
poolId: IDS.get(this),
poolConfig: {
min: (this.config.pool && this.config.pool.min) || 0,
max: (this.config.pool && this.config.pool.max) || 10
}
}), this, [callback])
return this
}
return tracePromise(CHANNELS.TRACE_CONNECT, () => {
return new shared.Promise((resolve, reject) => {
return this._connect(err => {
if (err) return reject(err)
resolve(this)
})
})
}, () => ({
server: this.config.server,
port: this.config.port,
database: this.config.database,
poolId: IDS.get(this),
poolConfig: {
min: (this.config.pool && this.config.pool.min) || 0,
max: (this.config.pool && this.config.pool.max) || 10
}
}))
}
/**
* @private
* @param {basicCallback} callback
*/
_connect (callback) {
if (this._connected) {
debug('pool(%d): already connected, executing connect callback immediately', IDS.get(this))
return setImmediate(callback, null, this)
}
this._connectStack.push(callback)
if (this._connecting) {
return
}
this._connecting = true
debug('pool(%d): connecting', IDS.get(this))
// create one test connection to check if everything is ok
this._poolCreate().then((connection) => {
debug('pool(%d): connected', IDS.get(this))
this._healthy = true
return this._poolDestroy(connection).then(() => {
// prepare pool
this.pool = new tarn.Pool(
Object.assign({
create: () => this._poolCreate()
.then(connection => {
this._healthy = true
return connection
})
.catch(err => {
if (this.pool.numUsed() + this.pool.numFree() <= 0) {
this._healthy = false
}
throw err
}),
validate: this._poolValidate.bind(this),
destroy: this._poolDestroy.bind(this),
max: 10,
min: 0,
idleTimeoutMillis: 30000,
propagateCreateError: true
}, this.config.pool)
)
this._connecting = false
this._connected = true
})
}).then(() => {
this._connectStack.forEach((cb) => {
setImmediate(cb, null, this)
})
}).catch(err => {
this._connecting = false
this._connectStack.forEach((cb) => {
setImmediate(cb, err)
})
}).then(() => {
this._connectStack = []
})
}
get size () {
return this.pool.numFree() + this.pool.numUsed() + this.pool.numPendingCreates()
}
get available () {
return this.pool.numFree()
}
get pending () {
return this.pool.numPendingAcquires()
}
get borrowed () {
return this.pool.numUsed()
}
/**
* Close all active connections in the pool.
*
* @param {basicCallback} [callback] A callback which is called after connection has closed, or an error has occurred. If omited, method returns Promise.
* @return {ConnectionPool|Promise}
*/
close (callback) {
if (typeof callback === 'function') {
this._close(callback)
return this
}
return new shared.Promise((resolve, reject) => {
this._close(err => {
if (err) return reject(err)
resolve(this)
})
})
}
/**
* @private
* @param {basicCallback} callback
*/
_close (callback) {
// we don't allow pools in a connecting state to be closed because it means there are far too many
// edge cases to deal with
if (this._connecting) {
debug('pool(%d): close called while connecting', IDS.get(this))
setImmediate(callback, new ConnectionError('Cannot close a pool while it is connecting'))
}
if (!this.pool) {
debug('pool(%d): already closed, executing close callback immediately', IDS.get(this))
return setImmediate(callback, null)
}
this._closeStack.push(callback)
if (this.pool.destroyed) return
this._connecting = this._connected = this._healthy = false
this.pool.destroy().then(() => {
debug('pool(%d): pool closed, removing pool reference and executing close callbacks', IDS.get(this))
publish(CHANNELS.POOL_CLOSE, () => ({
poolId: IDS.get(this),
reason: 'closed'
}))
this.pool = null
this._closeStack.forEach(cb => {
setImmediate(cb, null)
})
}).catch(err => {
publish(CHANNELS.POOL_CLOSE, () => ({
poolId: IDS.get(this),
reason: 'error',
error: err
}))
this.pool = null
this._closeStack.forEach(cb => {
setImmediate(cb, err)
})
}).then(() => {
this._closeStack = []
})
}
/**
* Returns new request using this connection.
*
* @param {{ requestTimeout?: number }} [conf] Per-request overrides.
* @return {Request}
*/
request (conf) {
return new shared.driver.Request(this, conf)
}
/**
* Returns new transaction using this connection.
*
* @param {{ requestTimeout?: number }} [conf] Per-transaction overrides, cascaded to child requests.
* @return {Transaction}
*/
transaction (conf) {
return new shared.driver.Transaction(this, conf)
}
/**
* Creates a new query using this connection from a tagged template string.
*
* @variation 1
* @param {Array} strings Array of string literals.
* @param {...*} keys Values.
* @return {Request}
*/
/**
* Execute the SQL command.
*
* @variation 2
* @param {String} command T-SQL command to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
query () {
if (typeof arguments[0] === 'string') { return new shared.driver.Request(this).query(arguments[0], arguments[1]) }
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
return new shared.driver.Request(this)._template(strings, values, 'query')
}
/**
* Creates a new batch using this connection from a tagged template string.
*
* @variation 1
* @param {Array} strings Array of string literals.
* @param {...*} keys Values.
* @return {Request}
*/
/**
* Execute the SQL command.
*
* @variation 2
* @param {String} command T-SQL command to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
batch () {
if (typeof arguments[0] === 'string') { return new shared.driver.Request(this).batch(arguments[0], arguments[1]) }
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
return new shared.driver.Request(this)._template(strings, values, 'batch')
}
}
module.exports = ConnectionPool

140
backend/node_modules/mssql/lib/base/index.js generated vendored Normal file
View File

@ -0,0 +1,140 @@
'use strict'
const ConnectionPool = require('./connection-pool')
const PreparedStatement = require('./prepared-statement')
const Request = require('./request')
const Transaction = require('./transaction')
const { ConnectionError, TransactionError, RequestError, PreparedStatementError, MSSQLError } = require('../error')
const shared = require('../shared')
const Table = require('../table')
const ISOLATION_LEVEL = require('../isolationlevel')
const { TYPES } = require('../datatypes')
const { connect, close, on, off, removeListener, query, batch } = require('../global-connection')
const { CHANNELS } = require('../diagnostics')
module.exports = {
ConnectionPool,
Transaction,
Request,
PreparedStatement,
ConnectionError,
TransactionError,
RequestError,
PreparedStatementError,
MSSQLError,
driver: shared.driver,
exports: {
ConnectionError,
TransactionError,
RequestError,
PreparedStatementError,
MSSQLError,
Table,
ISOLATION_LEVEL,
TYPES,
CHANNELS,
MAX: 65535, // (1 << 16) - 1
map: shared.map,
getTypeByValue: shared.getTypeByValue,
connect,
close,
on,
removeListener,
off,
query,
batch
}
}
Object.defineProperty(module.exports, 'Promise', {
enumerable: true,
get: () => {
return shared.Promise
},
set: (value) => {
shared.Promise = value
}
})
Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: shared.valueHandler,
writable: false,
configurable: false
})
for (const key in TYPES) {
const value = TYPES[key]
module.exports.exports[key] = value
module.exports.exports[key.toUpperCase()] = value
}
/**
* @callback Request~requestCallback
* @param {Error} err Error on error, otherwise null.
* @param {Object} [result] Request result.
*/
/**
* @callback Request~bulkCallback
* @param {Error} err Error on error, otherwise null.
* @param {Number} [rowsAffected] Number of affected rows.
*/
/**
* @callback basicCallback
* @param {Error} err Error on error, otherwise null.
* @param {Connection} [connection] Acquired connection.
*/
/**
* @callback acquireCallback
* @param {Error} err Error on error, otherwise null.
* @param {Connection} [connection] Acquired connection.
* @param {Object} [config] Connection config
*/
/**
* Dispatched after connection has established.
* @event ConnectionPool#connect
*/
/**
* Dispatched after connection has closed a pool (by calling close).
* @event ConnectionPool#close
*/
/**
* Dispatched when transaction begin.
* @event Transaction#begin
*/
/**
* Dispatched on successful commit.
* @event Transaction#commit
*/
/**
* Dispatched on successful rollback.
* @event Transaction#rollback
*/
/**
* Dispatched when metadata for new recordset are parsed.
* @event Request#recordset
*/
/**
* Dispatched when new row is parsed.
* @event Request#row
*/
/**
* Dispatched when request is complete.
* @event Request#done
*/
/**
* Dispatched on error.
* @event Request#error
*/

View File

@ -0,0 +1,436 @@
'use strict'
const debug = require('debug')('mssql:base')
const { EventEmitter } = require('node:events')
const { IDS, objectHasProperty, getPoolId } = require('../utils')
const globalConnection = require('../global-connection')
const { TransactionError, PreparedStatementError } = require('../error')
const shared = require('../shared')
const { TYPES, declare } = require('../datatypes')
const { CHANNELS, tracePromise, traceCallback, publish } = require('../diagnostics')
/**
* Class PreparedStatement.
*
* IMPORTANT: Rememeber that each prepared statement means one reserved connection from the pool. Don't forget to unprepare a prepared statement!
*
* @property {String} statement Prepared SQL statement.
*/
class PreparedStatement extends EventEmitter {
/**
* Creates a new Prepared Statement.
*
* @param {ConnectionPool|Transaction} [parent]
* @param {{ requestTimeout?: number }} [overrides]
*/
constructor (parent, overrides = {}) {
super()
IDS.add(this, 'PreparedStatement')
debug('ps(%d): created', IDS.get(this))
this.parent = parent || globalConnection.pool
this._handle = 0
this.prepared = false
this.parameters = {}
this.overrides = {}
if (Number.isFinite(overrides?.requestTimeout) && overrides.requestTimeout >= 0) {
this.overrides.requestTimeout = overrides.requestTimeout
}
}
get config () {
return this.parent.config
}
get connected () {
return this.parent.connected
}
/**
* Acquire connection from connection pool.
*
* @param {Request} request Request.
* @param {ConnectionPool~acquireCallback} [callback] A callback which is called after connection has established, or an error has occurred. If omited, method returns Promise.
* @return {PreparedStatement|Promise}
*/
acquire (request, callback) {
if (!this._acquiredConnection) {
setImmediate(callback, new PreparedStatementError('Statement is not prepared. Call prepare() first.', 'ENOTPREPARED'))
return this
}
if (this._activeRequest) {
setImmediate(callback, new TransactionError("Can't acquire connection for the request. There is another request in progress.", 'EREQINPROG'))
return this
}
this._activeRequest = request
setImmediate(callback, null, this._acquiredConnection, this._acquiredConfig)
return this
}
/**
* Release connection back to the pool.
*
* @param {Connection} connection Previously acquired connection.
* @return {PreparedStatement}
*/
release (connection) {
if (connection === this._acquiredConnection) {
this._activeRequest = null
}
return this
}
/**
* Add an input parameter to the prepared statement.
*
* @param {String} name Name of the input parameter without @ char.
* @param {*} type SQL data type of input parameter.
* @return {PreparedStatement}
*/
input (name, type) {
if (/--| |\/\*|\*\/|'/.test(name)) {
throw new PreparedStatementError(`SQL injection warning for param '${name}'`, 'EINJECT')
}
if (arguments.length < 2) {
throw new PreparedStatementError('Invalid number of arguments. 2 arguments expected.', 'EARGS')
}
if (type instanceof Function) {
type = type()
}
if (objectHasProperty(this.parameters, name)) {
throw new PreparedStatementError(`The parameter name ${name} has already been declared. Parameter names must be unique`, 'EDUPEPARAM')
}
this.parameters[name] = {
name,
type: type.type,
io: 1,
length: type.length,
scale: type.scale,
precision: type.precision,
tvpType: type.tvpType
}
return this
}
/**
* Replace an input parameter on the request.
*
* @param {String} name Name of the input parameter without @ char.
* @param {*} [type] SQL data type of input parameter. If you omit type, module automaticaly decide which SQL data type should be used based on JS data type.
* @param {*} value Input parameter value. `undefined` and `NaN` values are automatically converted to `null` values.
* @return {Request}
*/
replaceInput (name, type, value) {
delete this.parameters[name]
return this.input(name, type, value)
}
/**
* Add an output parameter to the prepared statement.
*
* @param {String} name Name of the output parameter without @ char.
* @param {*} type SQL data type of output parameter.
* @return {PreparedStatement}
*/
output (name, type) {
if (/--| |\/\*|\*\/|'/.test(name)) {
throw new PreparedStatementError(`SQL injection warning for param '${name}'`, 'EINJECT')
}
if (arguments.length < 2) {
throw new PreparedStatementError('Invalid number of arguments. 2 arguments expected.', 'EARGS')
}
if (type instanceof Function) type = type()
if (objectHasProperty(this.parameters, name)) {
throw new PreparedStatementError(`The parameter name ${name} has already been declared. Parameter names must be unique`, 'EDUPEPARAM')
}
this.parameters[name] = {
name,
type: type.type,
io: 2,
length: type.length,
scale: type.scale,
precision: type.precision
}
return this
}
/**
* Replace an output parameter on the request.
*
* @param {String} name Name of the output parameter without @ char.
* @param {*} type SQL data type of output parameter.
* @return {PreparedStatement}
*/
replaceOutput (name, type) {
delete this.parameters[name]
return this.output(name, type)
}
/**
* Prepare a statement.
*
* @param {String} statement SQL statement to prepare.
* @param {basicCallback} [callback] A callback which is called after preparation has completed, or an error has occurred. If omited, method returns Promise.
* @return {PreparedStatement|Promise}
*/
prepare (statement, callback) {
if (typeof callback === 'function') {
traceCallback(CHANNELS.TRACE_PREPARED_STATEMENT_PREPARE, this._prepare, 1, () => ({
statement: statement || this.statement,
parameters: Object.keys(this.parameters),
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}), this, [statement, callback])
return this
}
return tracePromise(CHANNELS.TRACE_PREPARED_STATEMENT_PREPARE, () => {
return new shared.Promise((resolve, reject) => {
this._prepare(statement, err => {
if (err) return reject(err)
resolve(this)
})
})
}, () => ({
statement: statement || this.statement,
parameters: Object.keys(this.parameters),
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}))
}
/**
* @private
* @param {String} statement
* @param {basicCallback} callback
*/
_prepare (statement, callback) {
debug('ps(%d): prepare', IDS.get(this))
if (typeof statement === 'function') {
callback = statement
statement = undefined
}
if (this.prepared) {
return setImmediate(callback, new PreparedStatementError('Statement is already prepared.', 'EALREADYPREPARED'))
}
this.statement = statement || this.statement
this.parent.acquire(this, (err, connection, config) => {
if (err) return callback(err)
this._acquiredConnection = connection
this._acquiredConfig = config
const req = new shared.driver.Request(this, this.overrides)
req._internal = true
req.stream = false
req.output('handle', TYPES.Int)
req.input('params', TYPES.NVarChar, ((() => {
const result = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
result.push(`@${name} ${declare(param.type, param)}${param.io === 2 ? ' output' : ''}`)
}
return result
})()).join(','))
req.input('stmt', TYPES.NVarChar, this.statement)
req.execute('sp_prepare', (err, result) => {
if (err) {
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
return callback(err)
}
debug('ps(%d): prepared', IDS.get(this))
this._handle = result.output.handle
this.prepared = true
callback(null)
})
})
}
/**
* Execute a prepared statement.
*
* @param {Object} values An object whose names correspond to the names of parameters that were added to the prepared statement before it was prepared.
* @param {basicCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
execute (values, callback) {
if (this.stream || (typeof callback === 'function')) {
if (typeof callback !== 'function') {
// Stream mode without a callback: no async boundary for traceCallback
// to hook — fall through to the untraced call. Subscribers interested
// in streaming completion should listen to Request events.
return this._execute(values, callback)
}
return traceCallback(CHANNELS.TRACE_PREPARED_STATEMENT_EXECUTE, this._execute, 1, () => ({
statement: this.statement,
parameters: Object.keys(this.parameters),
handle: this._handle,
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}), this, [values, callback])
}
return tracePromise(CHANNELS.TRACE_PREPARED_STATEMENT_EXECUTE, () => {
return new shared.Promise((resolve, reject) => {
this._execute(values, (err, recordset) => {
if (err) return reject(err)
resolve(recordset)
})
})
}, () => ({
statement: this.statement,
parameters: Object.keys(this.parameters),
handle: this._handle,
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}))
}
/**
* @private
* @param {Object} values
* @param {basicCallback} callback
*/
_execute (values, callback) {
const req = new shared.driver.Request(this, this.overrides)
req._internal = true
req.stream = this.stream
req.arrayRowMode = this.arrayRowMode
req.input('handle', TYPES.Int, this._handle)
// copy parameters with new values
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
req.parameters[name] = {
name,
type: param.type,
io: param.io,
value: values[name],
length: param.length,
scale: param.scale,
precision: param.precision
}
}
req.execute('sp_execute', typeof callback === 'function'
? callback
: () => {}
)
return req
}
/**
* Unprepare a prepared statement.
*
* @param {basicCallback} [callback] A callback which is called after unpreparation has completed, or an error has occurred. If omited, method returns Promise.
* @return {PreparedStatement|Promise}
*/
unprepare (callback) {
if (typeof callback === 'function') {
this._unprepare(err => {
if (!err) {
publish(CHANNELS.PREPARED_STATEMENT_UNPREPARE, () => ({
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}))
}
callback(err)
})
return this
}
return new shared.Promise((resolve, reject) => {
this._unprepare(err => {
if (err) return reject(err)
publish(CHANNELS.PREPARED_STATEMENT_UNPREPARE, () => ({
preparedStatementId: IDS.get(this),
poolId: getPoolId(this)
}))
resolve()
})
})
}
/**
* @private
* @param {basicCallback} callback
*/
_unprepare (callback) {
debug('ps(%d): unprepare', IDS.get(this))
if (!this.prepared) {
return setImmediate(callback, new PreparedStatementError('Statement is not prepared. Call prepare() first.', 'ENOTPREPARED'))
}
if (this._activeRequest) {
return setImmediate(callback, new TransactionError("Can't unprepare the statement. There is a request in progress.", 'EREQINPROG'))
}
const req = new shared.driver.Request(this, this.overrides)
req._internal = true
req.stream = false
req.input('handle', TYPES.Int, this._handle)
req.execute('sp_unprepare', err => {
if (err) return callback(err)
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
this._handle = 0
this.prepared = false
debug('ps(%d): unprepared', IDS.get(this))
return callback(null)
})
}
}
module.exports = PreparedStatement

722
backend/node_modules/mssql/lib/base/request.js generated vendored Normal file
View File

@ -0,0 +1,722 @@
'use strict'
const debug = require('debug')('mssql:base')
const { EventEmitter } = require('node:events')
const { Readable } = require('node:stream')
const { IDS, objectHasProperty, getPoolId } = require('../utils')
const globalConnection = require('../global-connection')
const { RequestError, ConnectionError } = require('../error')
const { TYPES } = require('../datatypes')
const shared = require('../shared')
const { CHANNELS, tracePromise, traceCallback, publish } = require('../diagnostics')
/**
* Class Request.
*
* @property {Transaction} transaction Reference to transaction when request was created in transaction.
* @property {*} parameters Collection of input and output parameters.
* @property {Boolean} canceled `true` if request was canceled.
*
* @fires Request#recordset
* @fires Request#row
* @fires Request#done
* @fires Request#error
*/
class Request extends EventEmitter {
/**
* Create new Request.
*
* @param {Connection|ConnectionPool|Transaction|PreparedStatement} [parent] If omitted, global connection is used instead.
* @param {{ requestTimeout?: number }} [overrides]
*/
constructor (parent, overrides = {}) {
super()
IDS.add(this, 'Request')
debug('request(%d): created', IDS.get(this))
this.canceled = false
this._paused = false
this._internal = false
this.parent = parent || globalConnection.pool
this.parameters = {}
this.stream = null
this.arrayRowMode = null
this.overrides = {}
if (Number.isFinite(overrides?.requestTimeout) && overrides.requestTimeout >= 0) {
this.overrides.requestTimeout = overrides.requestTimeout
}
}
get paused () {
return this._paused
}
/**
* Generate sql string and set input parameters from tagged template string.
*
* @param {Template literal} template
* @return {String}
*/
template () {
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
return this._template(strings, values)
}
/**
* Fetch request from tagged template string.
*
* @private
* @param {Array} strings
* @param {Array} values
* @param {String} [method] If provided, method is automatically called with serialized command on this object.
* @return {Request}
*/
_template (strings, values, method) {
const command = [strings[0]]
for (let index = 0; index < values.length; index++) {
const value = values[index]
// if value is an array, prepare each items as it's own comma separated parameter
if (Array.isArray(value)) {
for (let parameterIndex = 0; parameterIndex < value.length; parameterIndex++) {
this.input(`param${index + 1}_${parameterIndex}`, value[parameterIndex])
command.push(`@param${index + 1}_${parameterIndex}`)
if (parameterIndex < value.length - 1) {
command.push(', ')
}
}
command.push(strings[index + 1])
} else {
this.input(`param${index + 1}`, value)
command.push(`@param${index + 1}`, strings[index + 1])
}
}
if (method) {
return this[method](command.join(''))
} else {
return command.join('')
}
}
/**
* Add an input parameter to the request.
*
* @param {String} name Name of the input parameter without @ char.
* @param {*} [type] SQL data type of input parameter. If you omit type, module automatically decides which SQL data type should be used based on JS data type.
* @param {*} value Input parameter value. `undefined` and `NaN` values are automatically converted to `null` values.
* @return {Request}
*/
input (name, type, value) {
if (/--| |\/\*|\*\/|'/.test(name)) {
throw new RequestError(`SQL injection warning for param '${name}'`, 'EINJECT')
}
if (arguments.length < 2) {
throw new RequestError('Invalid number of arguments. At least 2 arguments expected.', 'EARGS')
} else if (arguments.length === 2) {
value = type
type = shared.getTypeByValue(value)
}
// support for custom data types
if (value && typeof value.valueOf === 'function' && !(value instanceof Date)) value = value.valueOf()
if (value === undefined) value = null // undefined to null
if (typeof value === 'number' && isNaN(value)) value = null // NaN to null
if (type instanceof Function) type = type()
if (objectHasProperty(this.parameters, name)) {
throw new RequestError(`The parameter name ${name} has already been declared. Parameter names must be unique`, 'EDUPEPARAM')
}
this.parameters[name] = {
name,
type: type.type,
io: 1,
value,
length: type.length,
scale: type.scale,
precision: type.precision,
tvpType: type.tvpType
}
return this
}
/**
* Replace an input parameter on the request.
*
* @param {String} name Name of the input parameter without @ char.
* @param {*} [type] SQL data type of input parameter. If you omit type, module automatically decides which SQL data type should be used based on JS data type.
* @param {*} value Input parameter value. `undefined` and `NaN` values are automatically converted to `null` values.
* @return {Request}
*/
replaceInput (name, type, value) {
delete this.parameters[name]
return this.input(name, type, value)
}
/**
* Add an output parameter to the request.
*
* @param {String} name Name of the output parameter without @ char.
* @param {*} type SQL data type of output parameter.
* @param {*} [value] Output parameter value initial value. `undefined` and `NaN` values are automatically converted to `null` values. Optional.
* @return {Request}
*/
output (name, type, value) {
if (!type) { type = TYPES.NVarChar }
if (/--| |\/\*|\*\/|'/.test(name)) {
throw new RequestError(`SQL injection warning for param '${name}'`, 'EINJECT')
}
if ((type === TYPES.Text) || (type === TYPES.NText) || (type === TYPES.Image)) {
throw new RequestError('Deprecated types (Text, NText, Image) are not supported as OUTPUT parameters.', 'EDEPRECATED')
}
// support for custom data types
if (value && typeof value.valueOf === 'function' && !(value instanceof Date)) value = value.valueOf()
if (value === undefined) value = null // undefined to null
if (typeof value === 'number' && isNaN(value)) value = null // NaN to null
if (type instanceof Function) type = type()
if (objectHasProperty(this.parameters, name)) {
throw new RequestError(`The parameter name ${name} has already been declared. Parameter names must be unique`, 'EDUPEPARAM')
}
this.parameters[name] = {
name,
type: type.type,
io: 2,
value,
length: type.length,
scale: type.scale,
precision: type.precision
}
return this
}
/**
* Replace an output parameter on the request.
*
* @param {String} name Name of the output parameter without @ char.
* @param {*} type SQL data type of output parameter.
* @param {*} [value] Output parameter value initial value. `undefined` and `NaN` values are automatically converted to `null` values. Optional.
* @return {Request}
*/
replaceOutput (name, type, value) {
delete this.parameters[name]
return this.output(name, type, value)
}
_getParameterNames () {
return Object.keys(this.parameters)
}
_tracedPromise (channel, contextFactory, fn) {
if (this._internal) {
return fn()
}
return tracePromise(channel, fn, contextFactory)
}
_tracedCallback (channel, contextFactory, fn, position, args) {
if (this._internal) {
return fn.apply(this, args)
}
return traceCallback(channel, fn, position, contextFactory, this, args)
}
/**
* Execute the SQL batch.
*
* @param {String} batch T-SQL batch to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
batch (batch, callback) {
if (this.stream === null && this.parent) this.stream = this.parent.config.stream
if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
this.rowsAffected = 0
if (typeof callback === 'function') {
this._tracedCallback(CHANNELS.TRACE_BATCH, () => ({
command: batch,
requestId: IDS.get(this),
poolId: getPoolId(this)
}), this._batch, 1, [batch, (err, recordsets, output, rowsAffected) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected
})
}
if (err) return callback(err)
callback(null, {
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected
})
}])
return this
}
// Check if method was called as tagged template
if (typeof batch === 'object') {
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
batch = this._template(strings, values)
}
const batchCommand = batch
return this._tracedPromise(CHANNELS.TRACE_BATCH, () => ({
command: batchCommand,
requestId: IDS.get(this),
poolId: getPoolId(this)
}), () => {
return new shared.Promise((resolve, reject) => {
this._batch(batchCommand, (err, recordsets, output, rowsAffected) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected
})
}
if (err) return reject(err)
resolve({
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected
})
})
})
})
}
/**
* @private
* @param {String} batch
* @param {Request~requestCallback} callback
*/
_batch (batch, callback) {
if (!this.parent) {
return setImmediate(callback, new RequestError('No connection is specified for that request.', 'ENOCONN'))
}
if (!this.parent.connected) {
return setImmediate(callback, new ConnectionError('Connection is closed.', 'ECONNCLOSED'))
}
this.canceled = false
setImmediate(callback)
}
/**
* Bulk load.
*
* @param {Table} table SQL table.
* @param {object} [options] Options to be passed to the underlying driver (tedious only).
* @param {Request~bulkCallback} [callback] A callback which is called after bulk load has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
bulk (table, options, callback) {
if (typeof options === 'function') {
callback = options
options = {}
} else if (typeof options === 'undefined') {
options = {}
}
if (this.stream === null && this.parent) this.stream = this.parent.config.stream
if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
if (this.stream || typeof callback === 'function') {
this._tracedCallback(CHANNELS.TRACE_BULK, () => ({
table: table.path || table.name,
rowCount: table.rows ? table.rows.length : 0,
requestId: IDS.get(this),
poolId: getPoolId(this)
}), this._bulk, 2, [table, options, (err, rowsAffected) => {
if (this.stream) {
if (err) this.emit('error', err)
return this.emit('done', {
rowsAffected
})
}
if (err) return callback(err)
callback(null, {
rowsAffected
})
}])
return this
}
return this._tracedPromise(CHANNELS.TRACE_BULK, () => ({
table: table.path || table.name,
rowCount: table.rows ? table.rows.length : 0,
requestId: IDS.get(this),
poolId: getPoolId(this)
}), () => {
return new shared.Promise((resolve, reject) => {
this._bulk(table, options, (err, rowsAffected) => {
if (err) return reject(err)
resolve({
rowsAffected
})
})
})
})
}
/**
* @private
* @param {Table} table
* @param {object} options
* @param {Request~bulkCallback} callback
*/
_bulk (table, options, callback) {
if (!this.parent) {
return setImmediate(callback, new RequestError('No connection is specified for that request.', 'ENOCONN'))
}
if (!this.parent.connected) {
return setImmediate(callback, new ConnectionError('Connection is closed.', 'ECONNCLOSED'))
}
this.canceled = false
setImmediate(callback)
}
/**
* Wrap original request in a Readable stream that supports back pressure and return.
* It also sets request to `stream` mode and pulls all rows from all recordsets to a given stream.
*
* @param {Object} streamOptions - optional options to configure the readable stream with like highWaterMark
* @return {Stream}
*/
toReadableStream (streamOptions = {}) {
this.stream = true
this.pause()
const readableStream = new Readable({
...streamOptions,
objectMode: true,
read: (/* size */) => {
this.resume()
}
})
this.on('row', (row) => {
if (!readableStream.push(row)) {
this.pause()
}
})
this.on('error', (error) => {
readableStream.emit('error', error)
})
this.on('done', () => {
readableStream.push(null)
})
return readableStream
}
/**
* Wrap original request in a Readable stream that supports back pressure and pipe to the Writable stream.
* It also sets request to `stream` mode and pulls all rows from all recordsets to a given stream.
*
* @param {Stream} stream Stream to pipe data into.
* @return {Stream}
*/
pipe (writableStream) {
const readableStream = this.toReadableStream()
return readableStream.pipe(writableStream)
}
/**
* Execute the SQL command.
*
* @param {String} command T-SQL command to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
query (command, callback) {
if (this.stream === null && this.parent) this.stream = this.parent.config.stream
if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
this.rowsAffected = 0
if (typeof callback === 'function') {
this._tracedCallback(CHANNELS.TRACE_QUERY, () => ({
command,
parameters: this._getParameterNames(),
requestId: IDS.get(this),
poolId: getPoolId(this)
}), this._query, 1, [command, (err, recordsets, output, rowsAffected, columns) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected
})
}
if (err) return callback(err)
const result = {
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected
}
if (this.arrayRowMode) result.columns = columns
callback(null, result)
}])
return this
}
// Check if method was called as tagged template
if (typeof command === 'object') {
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
command = this._template(strings, values)
}
return this._tracedPromise(CHANNELS.TRACE_QUERY, () => ({
command,
parameters: this._getParameterNames(),
requestId: IDS.get(this),
poolId: getPoolId(this)
}), () => {
return new shared.Promise((resolve, reject) => {
this._query(command, (err, recordsets, output, rowsAffected, columns) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected
})
}
if (err) return reject(err)
const result = {
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected
}
if (this.arrayRowMode) result.columns = columns
resolve(result)
})
})
})
}
/**
* @private
* @param {String} command
* @param {Request~bulkCallback} callback
*/
_query (command, callback) {
if (!this.parent) {
return setImmediate(callback, new RequestError('No connection is specified for that request.', 'ENOCONN'))
}
if (!this.parent.connected) {
return setImmediate(callback, new ConnectionError('Connection is closed.', 'ECONNCLOSED'))
}
this.canceled = false
setImmediate(callback)
}
/**
* Call a stored procedure.
*
* @param {String} procedure Name of the stored procedure to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
execute (command, callback) {
if (this.stream === null && this.parent) this.stream = this.parent.config.stream
if (this.arrayRowMode === null && this.parent) this.arrayRowMode = this.parent.config.arrayRowMode
this.rowsAffected = 0
if (typeof callback === 'function') {
this._tracedCallback(CHANNELS.TRACE_EXECUTE, () => ({
procedure: command,
parameters: this._getParameterNames(),
requestId: IDS.get(this),
poolId: getPoolId(this)
}), this._execute, 1, [command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected,
returnValue
})
}
if (err) return callback(err)
const result = {
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected,
returnValue
}
if (this.arrayRowMode) result.columns = columns
callback(null, result)
}])
return this
}
return this._tracedPromise(CHANNELS.TRACE_EXECUTE, () => ({
procedure: command,
parameters: this._getParameterNames(),
requestId: IDS.get(this),
poolId: getPoolId(this)
}), () => {
return new shared.Promise((resolve, reject) => {
this._execute(command, (err, recordsets, output, returnValue, rowsAffected, columns) => {
if (this.stream) {
if (err) this.emit('error', err)
err = null
this.emit('done', {
output,
rowsAffected,
returnValue
})
}
if (err) return reject(err)
const result = {
recordsets,
recordset: recordsets && recordsets[0],
output,
rowsAffected,
returnValue
}
if (this.arrayRowMode) result.columns = columns
resolve(result)
})
})
})
}
/**
* @private
* @param {String} procedure
* @param {Request~bulkCallback} callback
*/
_execute (procedure, callback) {
if (!this.parent) {
return setImmediate(callback, new RequestError('No connection is specified for that request.', 'ENOCONN'))
}
if (!this.parent.connected) {
return setImmediate(callback, new ConnectionError('Connection is closed.', 'ECONNCLOSED'))
}
this.canceled = false
setImmediate(callback)
}
/**
* Cancel currently executed request.
*
* @return {Boolean}
*/
cancel () {
this._cancel()
if (!this._internal) {
publish(CHANNELS.REQUEST_CANCEL, () => ({
requestId: IDS.get(this)
}))
}
return true
}
/**
* @private
*/
_cancel () {
this.canceled = true
}
pause () {
if (this.stream) {
this._pause()
return true
}
return false
}
_pause () {
this._paused = true
}
resume () {
if (this.stream) {
this._resume()
return true
}
return false
}
_resume () {
this._paused = false
}
_setCurrentRequest (request) {
this._currentRequest = request
if (this._paused) {
this.pause()
}
return this
}
}
module.exports = Request

323
backend/node_modules/mssql/lib/base/transaction.js generated vendored Normal file
View File

@ -0,0 +1,323 @@
'use strict'
const debug = require('debug')('mssql:base')
const { EventEmitter } = require('node:events')
const { IDS, getPoolId } = require('../utils')
const globalConnection = require('../global-connection')
const { TransactionError } = require('../error')
const shared = require('../shared')
const ISOLATION_LEVEL = require('../isolationlevel')
const { CHANNELS, publish } = require('../diagnostics')
const ISOLATION_LEVEL_NAMES = Object.fromEntries(
Object.entries(ISOLATION_LEVEL).map(([name, value]) => [value, name])
)
/**
* Class Transaction.
*
* @property {Number} isolationLevel Controls the locking and row versioning behavior of TSQL statements issued by a connection. READ_COMMITTED by default.
* @property {String} name Transaction name. Empty string by default.
*
* @fires Transaction#begin
* @fires Transaction#commit
* @fires Transaction#rollback
*/
class Transaction extends EventEmitter {
/**
* Create new Transaction.
*
* @param {Connection} [parent] If omitted, global connection is used instead.
* @param {{ requestTimeout?: number }} [overrides]
*/
constructor (parent, overrides = {}) {
super()
IDS.add(this, 'Transaction')
debug('transaction(%d): created', IDS.get(this))
this.parent = parent || globalConnection.pool
this.isolationLevel = Transaction.defaultIsolationLevel
this.name = ''
this.overrides = {}
if (Number.isFinite(overrides?.requestTimeout) && overrides.requestTimeout >= 0) {
this.overrides.requestTimeout = overrides.requestTimeout
}
}
get config () {
return this.parent.config
}
get connected () {
return this.parent.connected
}
/**
* Acquire connection from connection pool.
*
* @param {Request} request Request.
* @param {ConnectionPool~acquireCallback} [callback] A callback which is called after connection has established, or an error has occurred. If omited, method returns Promise.
* @return {Transaction|Promise}
*/
acquire (request, callback) {
if (!this._acquiredConnection) {
setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
return this
}
if (this._activeRequest) {
setImmediate(callback, new TransactionError("Can't acquire connection for the request. There is another request in progress.", 'EREQINPROG'))
return this
}
this._activeRequest = request
setImmediate(callback, null, this._acquiredConnection, this._acquiredConfig)
return this
}
/**
* Release connection back to the pool.
*
* @param {Connection} connection Previously acquired connection.
* @return {Transaction}
*/
release (connection) {
if (connection === this._acquiredConnection) {
this._activeRequest = null
}
return this
}
/**
* Begin a transaction.
*
* @param {Number} [isolationLevel] Controls the locking and row versioning behavior of TSQL statements issued by a connection.
* @param {basicCallback} [callback] A callback which is called after transaction has began, or an error has occurred. If omited, method returns Promise.
* @return {Transaction|Promise}
*/
begin (isolationLevel, callback) {
if (isolationLevel instanceof Function) {
callback = isolationLevel
isolationLevel = undefined
}
if (typeof callback === 'function') {
this._begin(isolationLevel, err => {
if (!err) {
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
transactionId: IDS.get(this),
isolationLevel: this.isolationLevel,
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
poolId: getPoolId(this)
}))
this.emit('begin')
}
callback(err)
})
return this
}
return new shared.Promise((resolve, reject) => {
this._begin(isolationLevel, err => {
if (err) return reject(err)
publish(CHANNELS.TRANSACTION_BEGIN, () => ({
transactionId: IDS.get(this),
isolationLevel: this.isolationLevel,
isolationLevelName: ISOLATION_LEVEL_NAMES[this.isolationLevel],
poolId: getPoolId(this)
}))
this.emit('begin')
resolve(this)
})
})
}
/**
* @private
* @param {Number} [isolationLevel]
* @param {basicCallback} [callback]
* @return {Transaction}
*/
_begin (isolationLevel, callback) {
if (this._acquiredConnection) {
return setImmediate(callback, new TransactionError('Transaction has already begun.', 'EALREADYBEGUN'))
}
this._aborted = false
this._abortReason = null
this._rollbackRequested = false
if (isolationLevel) {
if (Object.keys(ISOLATION_LEVEL).some(key => {
return ISOLATION_LEVEL[key] === isolationLevel
})) {
this.isolationLevel = isolationLevel
} else {
throw new TransactionError('Invalid isolation level.')
}
}
setImmediate(callback)
}
/**
* Commit a transaction.
*
* @param {basicCallback} [callback] A callback which is called after transaction has commited, or an error has occurred. If omited, method returns Promise.
* @return {Transaction|Promise}
*/
commit (callback) {
if (typeof callback === 'function') {
this._commit(err => {
if (!err) {
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
transactionId: IDS.get(this)
}))
this.emit('commit')
}
callback(err)
})
return this
}
return new shared.Promise((resolve, reject) => {
this._commit(err => {
if (err) return reject(err)
publish(CHANNELS.TRANSACTION_COMMIT, () => ({
transactionId: IDS.get(this)
}))
this.emit('commit')
resolve()
})
})
}
/**
* Creates a TransactionError for an aborted transaction, preserving the
* original abort reason (if any) as `originalError`.
*
* @private
* @return {TransactionError}
*/
_createAbortError () {
const err = new TransactionError('Transaction has been aborted.', 'EABORT')
if (this._abortReason) {
Object.defineProperty(err, 'originalError', { enumerable: true, value: this._abortReason })
}
return err
}
/**
* @private
* @param {basicCallback} [callback]
* @return {Transaction}
*/
_commit (callback) {
if (this._aborted) {
return setImmediate(callback, this._createAbortError())
}
if (!this._acquiredConnection) {
return setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
}
if (this._activeRequest) {
return setImmediate(callback, new TransactionError("Can't commit transaction. There is a request in progress.", 'EREQINPROG'))
}
setImmediate(callback)
}
/**
* Returns new request using this transaction.
*
* @param {{ requestTimeout?: number }} [config]
* @return {Request}
*/
request (config) {
const overrides = { ...this.overrides }
if (Number.isFinite(config?.requestTimeout) && config.requestTimeout >= 0) {
overrides.requestTimeout = config.requestTimeout
}
return new shared.driver.Request(this, overrides)
}
/**
* Rollback a transaction.
*
* @param {basicCallback} [callback] A callback which is called after transaction has rolled back, or an error has occurred. If omited, method returns Promise.
* @return {Transaction|Promise}
*/
rollback (callback) {
if (typeof callback === 'function') {
this._rollback(err => {
if (!err) {
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
transactionId: IDS.get(this),
aborted: this._aborted
}))
this.emit('rollback', this._aborted)
}
callback(err)
})
return this
}
return new shared.Promise((resolve, reject) => {
return this._rollback(err => {
if (err) return reject(err)
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
transactionId: IDS.get(this),
aborted: this._aborted
}))
this.emit('rollback', this._aborted)
resolve()
})
})
}
/**
* @private
* @param {basicCallback} [callback]
* @return {Transaction}
*/
_rollback (callback) {
if (this._aborted) {
return setImmediate(callback, this._createAbortError())
}
if (!this._acquiredConnection) {
return setImmediate(callback, new TransactionError('Transaction has not begun. Call begin() first.', 'ENOTBEGUN'))
}
if (this._activeRequest) {
return setImmediate(callback, new TransactionError("Can't rollback transaction. There is a request in progress.", 'EREQINPROG'))
}
this._rollbackRequested = true
setImmediate(callback)
}
}
/**
* Default isolation level used for any transactions that don't explicitly specify an isolation level.
*
* @type {number}
*/
Transaction.defaultIsolationLevel = ISOLATION_LEVEL.READ_COMMITTED
module.exports = Transaction

194
backend/node_modules/mssql/lib/datatypes.js generated vendored Normal file
View File

@ -0,0 +1,194 @@
'use strict'
const objectHasProperty = require('./utils').objectHasProperty
const inspect = Symbol.for('nodejs.util.inspect.custom')
const TYPES = {
VarChar (length) {
return { type: TYPES.VarChar, length }
},
NVarChar (length) {
return { type: TYPES.NVarChar, length }
},
Text () {
return { type: TYPES.Text }
},
Int () {
return { type: TYPES.Int }
},
BigInt () {
return { type: TYPES.BigInt }
},
TinyInt () {
return { type: TYPES.TinyInt }
},
SmallInt () {
return { type: TYPES.SmallInt }
},
Bit () {
return { type: TYPES.Bit }
},
Float () {
return { type: TYPES.Float }
},
Numeric (precision, scale) {
return { type: TYPES.Numeric, precision, scale }
},
Decimal (precision, scale) {
return { type: TYPES.Decimal, precision, scale }
},
Real () {
return { type: TYPES.Real }
},
Date () {
return { type: TYPES.Date }
},
DateTime () {
return { type: TYPES.DateTime }
},
DateTime2 (scale) {
return { type: TYPES.DateTime2, scale }
},
DateTimeOffset (scale) {
return { type: TYPES.DateTimeOffset, scale }
},
SmallDateTime () {
return { type: TYPES.SmallDateTime }
},
Time (scale) {
return { type: TYPES.Time, scale }
},
UniqueIdentifier () {
return { type: TYPES.UniqueIdentifier }
},
SmallMoney () {
return { type: TYPES.SmallMoney }
},
Money () {
return { type: TYPES.Money }
},
Binary (length) {
return { type: TYPES.Binary, length }
},
VarBinary (length) {
return { type: TYPES.VarBinary, length }
},
Image () {
return { type: TYPES.Image }
},
Xml () {
return { type: TYPES.Xml }
},
Char (length) {
return { type: TYPES.Char, length }
},
NChar (length) {
return { type: TYPES.NChar, length }
},
NText () {
return { type: TYPES.NText }
},
TVP (tvpType) {
return { type: TYPES.TVP, tvpType }
},
UDT () {
return { type: TYPES.UDT }
},
Geography () {
return { type: TYPES.Geography }
},
Geometry () {
return { type: TYPES.Geometry }
},
Variant () {
return { type: TYPES.Variant }
}
}
module.exports.TYPES = TYPES
module.exports.DECLARATIONS = {}
const zero = function (value, length) {
if (length == null) length = 2
value = String(value)
if (value.length < length) {
for (let i = 1; i <= length - value.length; i++) {
value = `0${value}`
}
}
return value
}
for (const key in TYPES) {
if (objectHasProperty(TYPES, key)) {
const value = TYPES[key]
value.declaration = key.toLowerCase()
module.exports.DECLARATIONS[value.declaration] = value;
((key, value) => {
value[inspect] = () => `[sql.${key}]`
})(key, value)
}
}
module.exports.declare = (type, options) => {
switch (type) {
case TYPES.VarChar: case TYPES.VarBinary:
return `${type.declaration} (${options.length > 8000 ? 'MAX' : (options.length == null ? 'MAX' : options.length)})`
case TYPES.NVarChar:
return `${type.declaration} (${options.length > 4000 ? 'MAX' : (options.length == null ? 'MAX' : options.length)})`
case TYPES.Char: case TYPES.NChar: case TYPES.Binary:
return `${type.declaration} (${options.length == null ? 1 : options.length})`
case TYPES.Decimal: case TYPES.Numeric:
return `${type.declaration} (${options.precision == null ? 18 : options.precision}, ${options.scale == null ? 0 : options.scale})`
case TYPES.Time: case TYPES.DateTime2: case TYPES.DateTimeOffset:
return `${type.declaration} (${options.scale == null ? 7 : options.scale})`
case TYPES.TVP:
return `${options.tvpType} readonly`
default:
return type.declaration
}
}
module.exports.cast = (value, type, options) => {
if (value == null) {
return null
}
switch (typeof value) {
case 'string':
return `N'${value.replace(/'/g, '\'\'')}'`
case 'number':
case 'bigint':
return value
case 'boolean':
return value ? 1 : 0
case 'object':
if (value instanceof Date) {
let ns = value.getUTCMilliseconds() / 1000
if (value.nanosecondDelta != null) {
ns += value.nanosecondDelta
}
const scale = options.scale == null ? 7 : options.scale
if (scale > 0) {
ns = String(ns).substr(1, scale + 1)
} else {
ns = ''
}
return `N'${value.getUTCFullYear()}-${zero(value.getUTCMonth() + 1)}-${zero(value.getUTCDate())} ${zero(value.getUTCHours())}:${zero(value.getUTCMinutes())}:${zero(value.getUTCSeconds())}${ns}'`
} else if (Buffer.isBuffer(value)) {
return `0x${value.toString('hex')}`
}
return null
default:
return null
}
}

153
backend/node_modules/mssql/lib/diagnostics.js generated vendored Normal file
View File

@ -0,0 +1,153 @@
'use strict'
const dc = require('node:diagnostics_channel')
// TracingChannel names
const TRACE_QUERY = 'mssql:query'
const TRACE_BATCH = 'mssql:batch'
const TRACE_EXECUTE = 'mssql:execute'
const TRACE_BULK = 'mssql:bulk'
const TRACE_CONNECT = 'mssql:connect'
const TRACE_POOL_ACQUIRE = 'mssql:pool:acquire'
const TRACE_PREPARED_STATEMENT_PREPARE = 'mssql:prepared-statement:prepare'
const TRACE_PREPARED_STATEMENT_EXECUTE = 'mssql:prepared-statement:execute'
// Point-event channel names
const CONNECTION_ACQUIRE = 'mssql:connection:acquire'
const CONNECTION_RELEASE = 'mssql:connection:release'
const CONNECTION_CREATE = 'mssql:connection:create'
const CONNECTION_DESTROY = 'mssql:connection:destroy'
const POOL_CLOSE = 'mssql:pool:close'
const TRANSACTION_BEGIN = 'mssql:transaction:begin'
const TRANSACTION_COMMIT = 'mssql:transaction:commit'
const TRANSACTION_ROLLBACK = 'mssql:transaction:rollback'
const REQUEST_CANCEL = 'mssql:request:cancel'
const PREPARED_STATEMENT_UNPREPARE = 'mssql:prepared-statement:unprepare'
const CHANNELS = Object.freeze({
TRACE_QUERY,
TRACE_BATCH,
TRACE_EXECUTE,
TRACE_BULK,
TRACE_CONNECT,
TRACE_POOL_ACQUIRE,
TRACE_PREPARED_STATEMENT_PREPARE,
TRACE_PREPARED_STATEMENT_EXECUTE,
CONNECTION_ACQUIRE,
CONNECTION_RELEASE,
CONNECTION_CREATE,
CONNECTION_DESTROY,
POOL_CLOSE,
TRANSACTION_BEGIN,
TRANSACTION_COMMIT,
TRANSACTION_ROLLBACK,
REQUEST_CANCEL,
PREPARED_STATEMENT_UNPREPARE
})
// Pre-create TracingChannel instances at module load time
const tracingChannels = {
[TRACE_QUERY]: dc.tracingChannel(TRACE_QUERY),
[TRACE_BATCH]: dc.tracingChannel(TRACE_BATCH),
[TRACE_EXECUTE]: dc.tracingChannel(TRACE_EXECUTE),
[TRACE_BULK]: dc.tracingChannel(TRACE_BULK),
[TRACE_CONNECT]: dc.tracingChannel(TRACE_CONNECT),
[TRACE_POOL_ACQUIRE]: dc.tracingChannel(TRACE_POOL_ACQUIRE),
[TRACE_PREPARED_STATEMENT_PREPARE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_PREPARE),
[TRACE_PREPARED_STATEMENT_EXECUTE]: dc.tracingChannel(TRACE_PREPARED_STATEMENT_EXECUTE)
}
// Pre-create point-event channel instances at module load time
const pointChannels = {
[CONNECTION_ACQUIRE]: dc.channel(CONNECTION_ACQUIRE),
[CONNECTION_RELEASE]: dc.channel(CONNECTION_RELEASE),
[CONNECTION_CREATE]: dc.channel(CONNECTION_CREATE),
[CONNECTION_DESTROY]: dc.channel(CONNECTION_DESTROY),
[POOL_CLOSE]: dc.channel(POOL_CLOSE),
[TRANSACTION_BEGIN]: dc.channel(TRANSACTION_BEGIN),
[TRANSACTION_COMMIT]: dc.channel(TRANSACTION_COMMIT),
[TRANSACTION_ROLLBACK]: dc.channel(TRANSACTION_ROLLBACK),
[REQUEST_CANCEL]: dc.channel(REQUEST_CANCEL),
[PREPARED_STATEMENT_UNPREPARE]: dc.channel(PREPARED_STATEMENT_UNPREPARE)
}
// TracingChannel.hasSubscribers was added in Node 22. On 18.19 / 20 the
// aggregate property is undefined, so we fall back to checking the
// sub-channels directly (these have existed since the original
// diagnostics_channel API). Preserves the zero-cost fast path across all
// supported runtimes.
function tracingChannelHasSubscribers (tc) {
if (typeof tc.hasSubscribers === 'boolean') return tc.hasSubscribers
return tc.start.hasSubscribers ||
tc.end.hasSubscribers ||
tc.asyncStart.hasSubscribers ||
tc.asyncEnd.hasSubscribers ||
tc.error.hasSubscribers
}
/**
* Trace an async operation using a TracingChannel.
*
* When subscribers are active, wraps `fn` with TracingChannel.tracePromise().
* When no subscribers are active, calls `fn` directly with zero overhead
* (no context allocation).
*
* @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
* @param {Function} fn - The function to trace (must return a Promise)
* @param {Function} contextFactory - Factory function returning the context object
* @returns {Promise} The return value of fn
*/
function tracePromise (name, fn, contextFactory) {
const channel = tracingChannels[name]
if (tracingChannelHasSubscribers(channel)) {
return channel.tracePromise(fn, contextFactory())
}
return fn()
}
/**
* Trace a callback-style async operation using a TracingChannel.
*
* When subscribers are active, delegates to TracingChannel.traceCallback,
* which replaces the callback at `position` in `args` with a wrapped
* version that publishes to start/end/asyncStart/asyncEnd/error. When
* no subscribers are active, calls `fn` directly with zero overhead.
*
* @param {string} name - TracingChannel name (one of CHANNELS.TRACE_*)
* @param {Function} fn - The function to call (receives callback at `position`)
* @param {number} position - Index of the callback within `args`
* @param {Function} contextFactory - Factory function returning the context object
* @param {*} thisArg - `this` binding for fn
* @param {Array} args - Arguments to pass to fn (includes the callback at `position`)
* @returns {*} The return value of fn
*/
function traceCallback (name, fn, position, contextFactory, thisArg, args) {
const channel = tracingChannels[name]
if (tracingChannelHasSubscribers(channel)) {
return channel.traceCallback(fn, position, contextFactory(), thisArg, ...args)
}
return fn.apply(thisArg, args)
}
/**
* Publish a point event on a named channel.
*
* Only allocates the message object when subscribers are active.
*
* @param {string} name - Point-event channel name (one of CHANNELS.*)
* @param {Function} factory - Factory function that returns the message object
*/
function publish (name, factory) {
const channel = pointChannels[name]
if (channel.hasSubscribers) {
channel.publish(factory())
}
}
module.exports = {
CHANNELS,
tracingChannels,
tracePromise,
traceCallback,
publish
}

View File

@ -0,0 +1,24 @@
'use strict'
const MSSQLError = require('./mssql-error')
/**
* Class ConnectionError.
*/
class ConnectionError extends MSSQLError {
/**
* Creates a new ConnectionError.
*
* @param {String} message Error message.
* @param {String} [code] Error code.
*/
constructor (message, code) {
super(message, code)
this.name = 'ConnectionError'
}
}
module.exports = ConnectionError

15
backend/node_modules/mssql/lib/error/index.js generated vendored Normal file
View File

@ -0,0 +1,15 @@
'use strict'
const ConnectionError = require('./connection-error')
const MSSQLError = require('./mssql-error')
const PreparedStatementError = require('./prepared-statement-error')
const RequestError = require('./request-error')
const TransactionError = require('./transaction-error')
module.exports = {
ConnectionError,
MSSQLError,
PreparedStatementError,
RequestError,
TransactionError
}

27
backend/node_modules/mssql/lib/error/mssql-error.js generated vendored Normal file
View File

@ -0,0 +1,27 @@
'use strict'
class MSSQLError extends Error {
/**
* Creates a new ConnectionError.
*
* @param {String} message Error message.
* @param {String} [code] Error code.
*/
constructor (message, code) {
if (message instanceof Error) {
super(message.message)
this.code = message.code || code
Error.captureStackTrace(this, this.constructor)
Object.defineProperty(this, 'originalError', { enumerable: true, value: message })
} else {
super(message)
this.code = code
}
this.name = 'MSSQLError'
}
}
module.exports = MSSQLError

View File

@ -0,0 +1,24 @@
'use strict'
const MSSQLError = require('./mssql-error')
/**
* Class PreparedStatementError.
*/
class PreparedStatementError extends MSSQLError {
/**
* Creates a new PreparedStatementError.
*
* @param {String} message Error message.
* @param {String} [code] Error code.
*/
constructor (message, code) {
super(message, code)
this.name = 'PreparedStatementError'
}
}
module.exports = PreparedStatementError

53
backend/node_modules/mssql/lib/error/request-error.js generated vendored Normal file
View File

@ -0,0 +1,53 @@
'use strict'
const MSSQLError = require('./mssql-error')
/**
* Class RequestError.
*
* @property {String} number Error number.
* @property {Number} lineNumber Line number.
* @property {String} state Error state.
* @property {String} class Error class.
* @property {String} serverName Server name.
* @property {String} procName Procedure name.
*/
class RequestError extends MSSQLError {
/**
* Creates a new RequestError.
*
* @param {String} message Error message.
* @param {String} [code] Error code.
*/
constructor (message, code) {
super(message, code)
if (message instanceof Error) {
if (message.info) {
this.number = message.info.number || message.code // err.code is returned by msnodesql driver
this.lineNumber = message.info.lineNumber
this.state = message.info.state || message.sqlstate // err.sqlstate is returned by msnodesql driver
this.class = message.info.class
this.serverName = message.info.serverName
this.procName = message.info.procName
} else {
// Use err attributes returned by msnodesql driver
this.number = message.code
this.lineNumber = message.lineNumber
this.state = message.sqlstate
this.class = message.severity
this.serverName = message.serverName
this.procName = message.procName
}
}
this.name = 'RequestError'
const parsedMessage = (/^\[Microsoft\]\[SQL Server Native Client 11\.0\](?:\[SQL Server\])?([\s\S]*)$/).exec(this.message)
if (parsedMessage) {
this.message = parsedMessage[1]
}
}
}
module.exports = RequestError

View File

@ -0,0 +1,24 @@
'use strict'
const MSSQLError = require('./mssql-error')
/**
* Class TransactionError.
*/
class TransactionError extends MSSQLError {
/**
* Creates a new TransactionError.
*
* @param {String} message Error message.
* @param {String} [code] Error code.
*/
constructor (message, code) {
super(message, code)
this.name = 'TransactionError'
}
}
module.exports = TransactionError

193
backend/node_modules/mssql/lib/global-connection.js generated vendored Normal file
View File

@ -0,0 +1,193 @@
'use strict'
const shared = require('./shared')
let globalConnection = null
const globalConnectionHandlers = {}
/**
* Open global connection pool.
*
* @param {Object|String} config Connection configuration object or connection string.
* @param {basicCallback} [callback] A callback which is called after connection has established, or an error has occurred. If omited, method returns Promise.
* @return {Promise.<ConnectionPool>}
*/
function connect (config, callback) {
if (!globalConnection) {
globalConnection = new shared.driver.ConnectionPool(config)
for (const event in globalConnectionHandlers) {
for (let i = 0, l = globalConnectionHandlers[event].length; i < l; i++) {
globalConnection.on(event, globalConnectionHandlers[event][i])
}
}
const ogClose = globalConnection.close
const globalClose = function (callback) {
// remove event handlers from the global connection
for (const event in globalConnectionHandlers) {
for (let i = 0, l = globalConnectionHandlers[event].length; i < l; i++) {
this.removeListener(event, globalConnectionHandlers[event][i])
}
}
// attach error handler to prevent process crash in case of error
this.on('error', err => {
if (globalConnectionHandlers.error) {
for (let i = 0, l = globalConnectionHandlers.error.length; i < l; i++) {
globalConnectionHandlers.error[i].call(this, err)
}
}
})
globalConnection = null
return ogClose.call(this, callback)
}
globalConnection.close = globalClose.bind(globalConnection)
}
if (typeof callback === 'function') {
return globalConnection.connect((err, connection) => {
if (err) {
globalConnection = null
}
callback(err, connection)
})
}
return globalConnection.connect().catch((err) => {
globalConnection = null
return shared.Promise.reject(err)
})
}
/**
* Close all active connections in the global pool.
*
* @param {basicCallback} [callback] A callback which is called after connection has closed, or an error has occurred. If omited, method returns Promise.
* @return {ConnectionPool|Promise}
*/
function close (callback) {
if (globalConnection) {
const gc = globalConnection
globalConnection = null
return gc.close(callback)
}
if (typeof callback === 'function') {
setImmediate(callback)
return null
}
return new shared.Promise((resolve) => {
resolve(globalConnection)
})
}
/**
* Attach event handler to global connection pool.
*
* @param {String} event Event name.
* @param {Function} handler Event handler.
* @return {ConnectionPool}
*/
function on (event, handler) {
if (!globalConnectionHandlers[event]) globalConnectionHandlers[event] = []
globalConnectionHandlers[event].push(handler)
if (globalConnection) globalConnection.on(event, handler)
return globalConnection
}
/**
* Detach event handler from global connection.
*
* @param {String} event Event name.
* @param {Function} handler Event handler.
* @return {ConnectionPool}
*/
function removeListener (event, handler) {
if (!globalConnectionHandlers[event]) return globalConnection
const index = globalConnectionHandlers[event].indexOf(handler)
if (index === -1) return globalConnection
globalConnectionHandlers[event].splice(index, 1)
if (globalConnectionHandlers[event].length === 0) globalConnectionHandlers[event] = undefined
if (globalConnection) globalConnection.removeListener(event, handler)
return globalConnection
}
/**
* Creates a new query using global connection from a tagged template string.
*
* @variation 1
* @param {Array|String} strings Array of string literals or sql command.
* @param {...*} keys Values.
* @return {Request}
*/
/**
* Execute the SQL command.
*
* @variation 2
* @param {String} command T-SQL command to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
function query () {
if (typeof arguments[0] === 'string') { return new shared.driver.Request().query(arguments[0], arguments[1]) }
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
return new shared.driver.Request()._template(strings, values, 'query')
}
/**
* Creates a new batch using global connection from a tagged template string.
*
* @variation 1
* @param {Array} strings Array of string literals.
* @param {...*} keys Values.
* @return {Request}
*/
/**
* Execute the SQL command.
*
* @variation 2
* @param {String} command T-SQL command to be executed.
* @param {Request~requestCallback} [callback] A callback which is called after execution has completed, or an error has occurred. If omited, method returns Promise.
* @return {Request|Promise}
*/
function batch () {
if (typeof arguments[0] === 'string') { return new shared.driver.Request().batch(arguments[0], arguments[1]) }
const values = Array.prototype.slice.call(arguments)
const strings = values.shift()
return new shared.driver.Request()._template(strings, values, 'batch')
}
module.exports = {
batch,
close,
connect,
off: removeListener,
on,
query,
removeListener
}
Object.defineProperty(module.exports, 'pool', {
get: () => {
return globalConnection
},
set: () => {}
})

9
backend/node_modules/mssql/lib/isolationlevel.js generated vendored Normal file
View File

@ -0,0 +1,9 @@
'use strict'
module.exports = {
READ_UNCOMMITTED: 0x01,
READ_COMMITTED: 0x02,
REPEATABLE_READ: 0x03,
SERIALIZABLE: 0x04,
SNAPSHOT: 0x05
}

View File

@ -0,0 +1,105 @@
'use strict'
const msnodesql = require('msnodesqlv8')
const debug = require('debug')('mssql:msv8')
const BaseConnectionPool = require('../base/connection-pool')
const { IDS, INCREMENT } = require('../utils')
const shared = require('../shared')
const ConnectionError = require('../error/connection-error')
const { platform } = require('node:os')
const { build } = require('@tediousjs/connection-string')
const { CHANNELS, publish } = require('../diagnostics')
const DEFAULT_CONNECTION_DRIVER = ['darwin', 'linux'].includes(platform()) ? 'ODBC Driver 17 for SQL Server' : 'SQL Server Native Client 11.0'
class ConnectionPool extends BaseConnectionPool {
_poolCreate () {
return new shared.Promise((resolve, reject) => {
this.config.requestTimeout = this.config.requestTimeout ?? this.config.timeout ?? 15000
const cfg = {
conn_str: this.config.connectionString,
conn_timeout: (this.config.connectionTimeout ?? this.config.timeout ?? 15000) / 1000
}
if (!this.config.connectionString) {
cfg.conn_str = build({
Driver: this.config.driver && this.config.driver !== 'msnodesqlv8' ? this.config.driver : DEFAULT_CONNECTION_DRIVER,
Server: this.config.options.instanceName ? `${this.config.server}\\${this.config.options.instanceName}` : `${this.config.server},${this.config.port}`,
Database: this.config.database,
Uid: this.config.user,
Pwd: this.config.password,
Trusted_Connection: !!this.config.options.trustedConnection,
Encrypt: !!this.config.options.encrypt
})
}
const connedtionId = INCREMENT.Connection++
debug('pool(%d): connection #%d created', IDS.get(this), connedtionId)
debug('connection(%d): establishing', connedtionId)
if (typeof this.config.beforeConnect === 'function') {
this.config.beforeConnect(cfg)
}
msnodesql.open(cfg, (err, tds) => {
if (err) {
let customErr = err?.details
if (customErr instanceof Array && (customErr = customErr.at(-1))) {
err.message = customErr.message
err.code = customErr.code
}
err = new ConnectionError(err.message, err.code)
return reject(err)
}
tds.setUseNumericString(true)
IDS.add(tds, 'Connection', connedtionId)
tds.setUseUTC(this.config.options.useUTC)
debug('connection(%d): established', IDS.get(tds))
publish(CHANNELS.CONNECTION_CREATE, () => ({
connectionId: IDS.get(tds),
poolId: IDS.get(this),
server: this.config.server,
database: this.config.database
}))
resolve(tds)
})
})
}
_poolValidate (tds) {
if (tds && !tds.hasError) {
return !this.config.validateConnection || new shared.Promise((resolve) => {
tds.query('SELECT 1;', (err) => {
resolve(!err)
})
})
}
return false
}
_poolDestroy (tds) {
return new shared.Promise((resolve, reject) => {
if (!tds) {
resolve()
return
}
const connectionId = IDS.get(tds)
const poolId = IDS.get(this)
debug('connection(%d): destroying', connectionId)
tds.close(() => {
debug('connection(%d): destroyed', connectionId)
publish(CHANNELS.CONNECTION_DESTROY, () => ({
connectionId,
poolId
}))
resolve()
})
})
}
}
module.exports = ConnectionPool

35
backend/node_modules/mssql/lib/msnodesqlv8/index.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
'use strict'
const base = require('../base')
const ConnectionPool = require('./connection-pool')
const Transaction = require('./transaction')
const Request = require('./request')
module.exports = Object.assign({
ConnectionPool,
Transaction,
Request,
PreparedStatement: base.PreparedStatement
}, base.exports)
Object.defineProperty(module.exports, 'Promise', {
enumerable: true,
get: () => {
return base.Promise
},
set: (value) => {
base.Promise = value
}
})
Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: base.valueHandler,
writable: false,
configurable: false
})
base.driver.name = 'msnodesqlv8'
base.driver.ConnectionPool = ConnectionPool
base.driver.Transaction = Transaction
base.driver.Request = Request

784
backend/node_modules/mssql/lib/msnodesqlv8/request.js generated vendored Normal file
View File

@ -0,0 +1,784 @@
'use strict'
const msnodesql = require('msnodesqlv8')
const debug = require('debug')('mssql:msv8')
const BaseRequest = require('../base/request')
const RequestError = require('../error/request-error')
const { IDS, objectHasProperty } = require('../utils')
const { TYPES, DECLARATIONS, declare } = require('../datatypes')
const { PARSERS: UDT } = require('../udt')
const Table = require('../table')
const { valueHandler } = require('../shared')
const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
const XML_COLUMN_ID = 'XML_F52E2B61-18A1-11d1-B105-00805F49916B'
const EMPTY_BUFFER = Buffer.alloc(0)
const castParameter = function (value, type) {
if (value == null) {
if ((type === TYPES.Binary) || (type === TYPES.VarBinary) || (type === TYPES.Image)) {
// msnodesql has some problems with NULL values in those types, so we need to replace it with empty buffer
return EMPTY_BUFFER
}
return null
}
switch (type) {
case TYPES.VarChar:
case TYPES.NVarChar:
case TYPES.Char:
case TYPES.NChar:
case TYPES.Xml:
case TYPES.Text:
case TYPES.BigInt:
case TYPES.NText:
if ((typeof value !== 'string') && !(value instanceof String)) {
value = value.toString()
}
break
case TYPES.Int:
case TYPES.TinyInt:
case TYPES.SmallInt:
if ((typeof value !== 'number') && !(value instanceof Number)) {
value = parseInt(value)
if (isNaN(value)) { value = null }
}
break
case TYPES.Float:
case TYPES.Real:
case TYPES.Decimal:
case TYPES.Numeric:
case TYPES.SmallMoney:
case TYPES.Money:
if ((typeof value !== 'number') && !(value instanceof Number)) {
value = parseFloat(value)
if (isNaN(value)) { value = null }
}
break
case TYPES.Bit:
if ((typeof value !== 'boolean') && !(value instanceof Boolean)) {
value = Boolean(value)
}
break
case TYPES.DateTime:
case TYPES.SmallDateTime:
case TYPES.DateTimeOffset:
case TYPES.Date:
if (!(value instanceof Date)) {
value = new Date(value)
}
break
case TYPES.Binary:
case TYPES.VarBinary:
case TYPES.Image:
if (!(value instanceof Buffer)) {
value = Buffer.from(value.toString())
}
break
case TYPES.TVP:
value = msnodesql.TvpFromTable(value)
break
}
return value
}
const createColumns = function (metadata, arrayRowMode) {
let out = {}
if (arrayRowMode) out = []
for (let index = 0, length = metadata.length; index < length; index++) {
const column = metadata[index]
const colName = column.name
const outColumn = {
index,
name: column.name,
length: column.size,
type: DECLARATIONS[column.sqlType],
nullable: column.nullable
}
if (column.udtType != null) {
outColumn.udt = {
name: column.udtType
}
if (DECLARATIONS[column.udtType]) {
outColumn.type = DECLARATIONS[column.udtType]
}
}
if (arrayRowMode) {
out.push(outColumn)
} else {
out[colName] = outColumn
}
}
return out
}
const numericStringSqlTypes = new Set(['int', 'smallint', 'tinyint', 'float', 'real', 'numeric', 'decimal', 'money', 'smallmoney'])
const valueCorrection = function (value, metadata) {
const type = metadata && objectHasProperty(metadata, 'sqlType') && objectHasProperty(DECLARATIONS, metadata.sqlType)
? DECLARATIONS[metadata.sqlType]
: null
if (type && valueHandler.has(type)) {
return valueHandler.get(type)(value)
} else if ((metadata.sqlType === 'time') && (value != null)) {
value.setFullYear(1970)
return value
} else if ((metadata.sqlType === 'udt') && (value != null)) {
if (UDT[metadata.udtType]) {
return UDT[metadata.udtType](value)
} else {
return value
}
} else if (typeof value === 'string' && numericStringSqlTypes.has(metadata.sqlType)) {
return Number(value)
} else if (typeof value === 'string' && metadata.sqlType === 'sql_variant' && value !== '' && !isNaN(Number(value))) {
return Number(value)
} else {
return value
}
}
class Request extends BaseRequest {
_batch (batch, callback) {
this._isBatch = true
this._query(batch, callback)
}
_bulk (table, options, callback) {
super._bulk(table, options, err => {
if (err) return callback(err)
try {
table._makeBulk()
} catch (e) {
return callback(new RequestError(e, 'EREQUEST'))
}
if (!table.name) {
setImmediate(callback, new RequestError('Table name must be specified for bulk insert.', 'ENAME'))
}
if (table.name.charAt(0) === '@') {
setImmediate(callback, new RequestError("You can't use table variables for bulk insert.", 'ENAME'))
}
this.parent.acquire(this, (err, connection, config) => {
let hasReturned = false
if (!err) {
debug('connection(%d): borrowed to request #%d', IDS.get(connection), IDS.get(this))
if (this.canceled) {
debug('request(%d): canceled', IDS.get(this))
this.parent.release(connection)
return callback(new RequestError('Canceled.', 'ECANCEL'))
}
// Disable useNumericString during bulk operations to avoid
// msnodesqlv8 SQL generation bugs with its table manager
connection.setUseNumericString(false)
const done = (err, rowCount) => {
if (hasReturned) {
return
}
hasReturned = true
connection.setUseNumericString(true)
if (err) {
if ((typeof err.sqlstate === 'string') && (err.sqlstate.toLowerCase() === '08s01')) {
connection.hasError = true
}
err = new RequestError(err)
err.code = 'EREQUEST'
}
this.parent.release(connection)
if (err) {
callback(err)
} else {
callback(null, table.rows.length)
}
}
const go = () => {
const tm = connection.tableMgr()
return tm.bind(table.path.replace(/\[|\]/g, ''), mgr => {
if (mgr.columns.length === 0) {
return done(new RequestError('Table was not found on the server.', 'ENAME'))
}
const rows = []
for (const row of Array.from(table.rows)) {
const item = {}
for (let index = 0; index < table.columns.length; index++) {
const col = table.columns[index]
item[col.name] = row[index]
}
rows.push(item)
}
mgr.insertRows(rows, done)
})
}
if (table.create) {
let objectid
if (table.temporary) {
objectid = `tempdb..[${table.name}]`
} else {
objectid = table.path
}
return connection.queryRaw({
query_str: `if object_id('${objectid.replace(/'/g, '\'\'')}') is null ${table.declare()}`,
query_timeout: (this.overrides.requestTimeout ?? config.requestTimeout) / 1000 // msnodesqlv8 timeouts are in seconds (<1 second not supported)
}, function (err) {
if (err) { return done(err) }
go()
})
} else {
go()
}
}
})
})
}
_query (command, callback) {
super._query(command, err => {
if (err) return callback(err)
if (command.length === 0) {
return callback(null, [])
}
const recordsets = []
const recordsetcolumns = []
const errors = []
const errorHandlers = {}
const output = {}
const rowsAffected = []
let hasReturned = false
let row = null
let columns = null
let recordset = null
let handleOutput = false
let isChunkedRecordset = false
let chunksBuffer = null
const handleError = (req, connection, info, moreErrors) => {
const doReturn = !moreErrors
if ((typeof info.sqlstate === 'string') && (info.sqlstate.toLowerCase() === '08s01')) {
connection.hasError = true
}
const err = new RequestError(info, 'EREQUEST')
err.code = 'EREQUEST'
if (this.stream) {
this.emit('error', err)
} else {
if (doReturn && !hasReturned) {
if (req) {
for (const event in errorHandlers) {
req.removeListener(event, errorHandlers[event])
}
}
if (connection) {
this.parent.release(connection)
delete this._cancel
debug('request(%d): failed', IDS.get(this), err)
}
let previous
if (errors.length) {
previous = errors.pop()
if (!err.precedingErrors) {
err.precedingErrors = []
}
err.precedingErrors.push(previous)
}
hasReturned = true
callback(err)
}
}
// we must collect errors even in stream mode
errors.push(err)
}
// nested = function is called by this.execute
if (!this._nested) {
const input = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
input.push(`@${param.name} ${declare(param.type, param)}`)
}
const sets = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 1) {
sets.push(`set @${param.name}=?`)
}
}
const output = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
output.push(`@${param.name} as '${param.name}'`)
}
}
if (input.length) command = `declare ${input.join(',')};${sets.join(';')};${command};`
if (output.length) {
command += `select ${output.join(',')};`
handleOutput = true
}
}
this.parent.acquire(this, (err, connection, config) => {
if (err) return callback(err)
debug('connection(%d): borrowed to request #%d', IDS.get(connection), IDS.get(this))
if (this.canceled) {
debug('request(%d): canceled', IDS.get(this))
this.parent.release(connection)
return callback(new RequestError('Canceled.', 'ECANCEL'))
}
const params = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 1 || (param.io === 2 && param.value)) {
params.push(castParameter(param.value, param.type))
}
}
debug('request(%d): query', IDS.get(this), command)
const req = connection.queryRaw({
query_str: command,
query_timeout: (this.overrides.requestTimeout ?? config.requestTimeout) / 1000 // msnodesqlv8 timeouts are in seconds (<1 second not supported)
}, params)
this._setCurrentRequest(req)
this._cancel = () => {
debug('request(%d): cancel', IDS.get(this))
req.cancelQuery(err => {
if (err) debug('request(%d): failed to cancel', IDS.get(this), err)
// this fixes an issue where paused connections don't emit a done event
try {
if (req.isPaused()) req.emit('done')
} catch (err) {
// do nothing
}
})
}
req.on('meta', metadata => {
if (row) {
if (isChunkedRecordset) {
const concatenatedChunks = chunksBuffer.join('')
if ((columns[0].name === JSON_COLUMN_ID) && (config.parseJSON === true)) {
try {
if (concatenatedChunks === '') {
row = null
} else {
row = JSON.parse(concatenatedChunks)
}
if (!this.stream) { recordsets[recordsets.length - 1][0] = row }
} catch (ex) {
row = null
const ex2 = new RequestError(`Failed to parse incoming JSON. ${ex.message}`, 'EJSON')
if (this.stream) {
this.emit('error', ex2)
} else {
console.error(ex2)
}
}
} else {
row[columns[0].name] = concatenatedChunks
}
chunksBuffer = null
if (row && row.___return___ == null) {
// row with ___return___ col is the last row
if (this.stream && !this.paused) this.emit('row', row)
}
}
}
row = null
columns = metadata
recordset = []
Object.defineProperty(recordset, 'columns', {
enumerable: false,
configurable: true,
value: createColumns(metadata, this.arrayRowMode)
})
Object.defineProperty(recordset, 'toTable', {
enumerable: false,
configurable: true,
value (name) { return Table.fromRecordset(this, name) }
})
isChunkedRecordset = false
if ((metadata.length === 1) && (metadata[0].name === JSON_COLUMN_ID || metadata[0].name === XML_COLUMN_ID)) {
isChunkedRecordset = true
chunksBuffer = []
}
let hasReturnColumn = false
if (recordset.columns.___return___ != null) {
hasReturnColumn = true
} else if (this.arrayRowMode) {
for (let i = 0; i < columns.length; i++) {
if (columns[i].name === '___return___') {
hasReturnColumn = true
break
}
}
}
if (this.stream) {
if (!hasReturnColumn) {
this.emit('recordset', recordset.columns)
}
} else {
recordsets.push(recordset)
}
if (this.arrayRowMode) recordsetcolumns.push(recordset.columns)
})
req.on('row', rownumber => {
if (row && isChunkedRecordset) return
if (this.arrayRowMode) {
row = []
} else {
row = {}
}
if (!this.stream) recordset.push(row)
})
req.on('column', (idx, data, more) => {
if (isChunkedRecordset) {
chunksBuffer.push(data)
} else {
data = valueCorrection(data, columns[idx])
if (this.arrayRowMode) {
row.push(data)
} else {
const exi = row[columns[idx].name]
if (exi != null) {
if (exi instanceof Array) {
exi.push(data)
} else {
row[columns[idx].name] = [exi, data]
}
} else {
row[columns[idx].name] = data
}
}
let hasReturnColumn = false
if (row && row.___return___ != null) {
hasReturnColumn = true
} else if (this.arrayRowMode) {
for (let i = 0; i < columns.length; i++) {
if (columns[i].name === '___return___') {
hasReturnColumn = true
break
}
}
}
if (!hasReturnColumn) {
if (this.stream && !this.paused && idx === columns.length - 1) {
this.emit('row', row)
}
}
}
})
req.on('rowcount', rowCount => {
rowsAffected.push(rowCount)
if (this.stream) {
this.emit('rowsaffected', rowCount)
}
})
req.on('info', msg => {
const parsedMessage = (/^\[Microsoft\]\[SQL Server Native Client 11\.0\](?:\[SQL Server\])?([\s\S]*)$/).exec(msg.message)
if (parsedMessage) {
msg.message = parsedMessage[1]
}
this.emit('info', {
message: msg.message,
number: msg.code,
state: msg.sqlstate,
class: msg.class || 0,
lineNumber: msg.lineNumber || 0,
serverName: msg.serverName,
procName: msg.procName
})
// query terminated
if (msg.code === 3621 && !hasReturned) {
// if the query has been terminated it's probably best to throw the last meaningful error if there was one
// pop it off the errors array so it doesn't get put in twice
const error = errors.length > 0 ? errors.pop() : msg
handleError(req, connection, error.originalError || error, false)
}
})
req.on('error', errorHandlers.error = handleError.bind(null, req, connection))
req.once('done', () => {
if (hasReturned) {
return
}
hasReturned = true
if (!this._nested) {
if (row) {
if (isChunkedRecordset) {
const concatenatedChunks = chunksBuffer.join('')
if ((columns[0].name === JSON_COLUMN_ID) && (config.parseJSON === true)) {
try {
if (concatenatedChunks === '') {
row = null
} else {
row = JSON.parse(concatenatedChunks)
}
if (!this.stream) { recordsets[recordsets.length - 1][0] = row }
} catch (ex) {
row = null
const ex2 = new RequestError(`Failed to parse incoming JSON. ${ex.message}`, 'EJSON')
if (this.stream) {
this.emit('error', ex2)
} else {
console.error(ex2)
}
}
} else {
row[columns[0].name] = concatenatedChunks
}
chunksBuffer = null
if (row && row.___return___ == null) {
// row with ___return___ col is the last row
if (this.stream && !this.paused) { this.emit('row', row) }
}
}
}
// do we have output parameters to handle?
if (handleOutput && recordsets.length) {
const last = recordsets.pop()[0]
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
output[param.name] = last[param.name]
}
}
}
}
delete this._cancel
this.parent.release(connection)
debug('request(%d): completed', IDS.get(this))
if (this.stream) {
callback(null, this._nested ? row : null, output, rowsAffected, recordsetcolumns)
} else {
callback(null, recordsets, output, rowsAffected, recordsetcolumns)
}
})
})
})
}
_execute (procedure, callback) {
super._execute(procedure, err => {
if (err) return callback(err)
const params = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
params.push(`@${param.name} ${declare(param.type, param)}`)
}
}
// set output params w/ values
const sets = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2 && param.value) {
sets.push(`set @${param.name}=?`)
}
}
let cmd = `declare ${['@___return___ int'].concat(params).join(', ')};${sets.join(';')};`
cmd += `exec @___return___ = ${procedure} `
const spp = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
// output parameter
spp.push(`@${param.name}=@${param.name} output`)
} else {
// input parameter
spp.push(`@${param.name}=?`)
}
}
const params2 = []
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
params2.push(`@${param.name} as '${param.name}'`)
}
}
cmd += `${spp.join(', ')};`
cmd += `select ${['@___return___ as \'___return___\''].concat(params2).join(', ')};`
this._nested = true
this._query(cmd, (err, recordsets, output, rowsAffected, recordsetcolumns) => {
this._nested = false
if (err) return callback(err)
let last, returnValue
if (this.stream) {
last = recordsets
} else {
last = recordsets.pop()
if (last) last = last[0]
}
const lastColumns = recordsetcolumns.pop()
if (last && this.arrayRowMode && lastColumns) {
let returnColumnIdx = null
const parametersNameToLastIdxDict = {}
for (let i = 0; i < lastColumns.length; i++) {
if (lastColumns[i].name === '___return___') {
returnColumnIdx = i
} else if (objectHasProperty(this.parameters, lastColumns[i].name)) {
parametersNameToLastIdxDict[lastColumns[i].name] = i
}
}
if (returnColumnIdx != null) {
returnValue = last[returnColumnIdx]
}
for (const name in parametersNameToLastIdxDict) {
if (!objectHasProperty(parametersNameToLastIdxDict, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
output[param.name] = last[parametersNameToLastIdxDict[name]]
}
}
} else {
if (last && (last.___return___ != null)) {
returnValue = last.___return___
for (const name in this.parameters) {
if (!objectHasProperty(this.parameters, name)) {
continue
}
const param = this.parameters[name]
if (param.io === 2) {
output[param.name] = last[param.name]
}
}
}
}
if (this.stream) {
callback(null, null, output, returnValue, rowsAffected, recordsetcolumns)
} else {
callback(null, recordsets, output, returnValue, rowsAffected, recordsetcolumns)
}
})
})
}
_pause () {
super._pause()
if (this._currentRequest) {
this._currentRequest.pauseQuery()
}
}
_resume () {
super._resume()
if (this._currentRequest) {
this._currentRequest.resumeQuery()
}
}
}
module.exports = Request

View File

@ -0,0 +1,98 @@
'use strict'
const debug = require('debug')('mssql:msv8')
const BaseTransaction = require('../base/transaction')
const { IDS } = require('../utils')
const Request = require('./request')
const ISOLATION_LEVEL = require('../isolationlevel')
const TransactionError = require('../error/transaction-error')
const isolationLevelDeclaration = function (type) {
switch (type) {
case ISOLATION_LEVEL.READ_UNCOMMITTED: return 'READ UNCOMMITTED'
case ISOLATION_LEVEL.READ_COMMITTED: return 'READ COMMITTED'
case ISOLATION_LEVEL.REPEATABLE_READ: return 'REPEATABLE READ'
case ISOLATION_LEVEL.SERIALIZABLE: return 'SERIALIZABLE'
case ISOLATION_LEVEL.SNAPSHOT: return 'SNAPSHOT'
default: throw new TransactionError('Invalid isolation level.')
}
}
class Transaction extends BaseTransaction {
_begin (isolationLevel, callback) {
super._begin(isolationLevel, err => {
if (err) return callback(err)
debug('transaction(%d): begin', IDS.get(this))
this.parent.acquire(this, (err, connection, config) => {
if (err) return callback(err)
this._acquiredConnection = connection
this._acquiredConfig = config
const req = new Request(this)
req.stream = false
req.query(`set transaction isolation level ${isolationLevelDeclaration(this.isolationLevel)};begin tran;`, err => {
if (err) {
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
return callback(err)
}
debug('transaction(%d): begun', IDS.get(this))
callback(null)
})
})
})
}
_commit (callback) {
super._commit(err => {
if (err) return callback(err)
debug('transaction(%d): commit', IDS.get(this))
const req = new Request(this)
req.stream = false
req.query('commit tran', err => {
if (err) err = new TransactionError(err)
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
if (!err) debug('transaction(%d): commited', IDS.get(this))
callback(null)
})
})
}
_rollback (callback) {
super._commit(err => {
if (err) return callback(err)
debug('transaction(%d): rollback', IDS.get(this))
const req = new Request(this)
req.stream = false
req.query('rollback tran', err => {
if (err) err = new TransactionError(err)
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
if (!err) debug('transaction(%d): rolled back', IDS.get(this))
callback(null)
})
})
}
}
module.exports = Transaction

120
backend/node_modules/mssql/lib/shared.js generated vendored Normal file
View File

@ -0,0 +1,120 @@
'use strict'
const { TYPES } = require('./datatypes')
const Table = require('./table')
let PromiseLibrary = Promise
const driver = {}
const map = []
/**
* Register you own type map.
*
* @path module.exports.map
* @param {*} jstype JS data type.
* @param {*} sqltype SQL data type.
*/
map.register = function (jstype, sqltype) {
for (let index = 0; index < this.length; index++) {
const item = this[index]
if (item.js === jstype) {
this.splice(index, 1)
break
}
}
this.push({
js: jstype,
sql: sqltype
})
return null
}
map.register(String, TYPES.NVarChar)
map.register(Number, TYPES.Int)
map.register(Boolean, TYPES.Bit)
map.register(Date, TYPES.DateTime)
map.register(Buffer, TYPES.VarBinary)
map.register(Table, TYPES.TVP)
/**
* @ignore
*/
const getTypeByValue = function (value) {
if ((value === null) || (value === undefined)) { return TYPES.NVarChar }
switch (typeof value) {
case 'string':
for (const item of Array.from(map)) {
if (item.js === String) {
return item.sql
}
}
return TYPES.NVarChar
case 'number':
if (value % 1 === 0) {
if (value < -2147483648 || value > 2147483647) {
return TYPES.BigInt
} else {
return TYPES.Int
}
} else {
return TYPES.Float
}
case 'bigint':
if (value < -2147483648n || value > 2147483647n) {
return TYPES.BigInt
} else {
return TYPES.Int
}
case 'boolean':
for (const item of Array.from(map)) {
if (item.js === Boolean) {
return item.sql
}
}
return TYPES.Bit
case 'object':
for (const item of Array.from(map)) {
if (value instanceof item.js) {
return item.sql
}
}
return TYPES.NVarChar
default:
return TYPES.NVarChar
}
}
module.exports = {
driver,
getTypeByValue,
map
}
Object.defineProperty(module.exports, 'Promise', {
get: () => {
return PromiseLibrary
},
set: (value) => {
PromiseLibrary = value
}
})
Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: new Map(),
writable: false,
configurable: false
})

220
backend/node_modules/mssql/lib/table.js generated vendored Normal file
View File

@ -0,0 +1,220 @@
'use strict'
const TYPES = require('./datatypes').TYPES
const declareType = require('./datatypes').declare
const objectHasProperty = require('./utils').objectHasProperty
const MAX = 65535 // (1 << 16) - 1
const JSON_COLUMN_ID = 'JSON_F52E2B61-18A1-11d1-B105-00805F49916B'
function Table (name) {
if (name) {
const parsed = Table.parseName(name)
this.name = parsed.name
this.schema = parsed.schema
this.database = parsed.database
this.path = (this.database ? `[${this.database}].` : '') + (this.schema ? `[${this.schema}].` : '') + `[${this.name}]`
this.temporary = this.name.charAt(0) === '#'
}
this.columns = []
this.rows = []
Object.defineProperty(this.columns, 'add', {
value (name, column, options) {
if (column == null) {
throw new Error('Column data type is not defined.')
}
if (column instanceof Function) {
column = column()
}
options = options || {}
column.name = name;
['nullable', 'primary', 'identity', 'readOnly', 'length'].forEach(prop => {
if (objectHasProperty(options, prop)) {
column[prop] = options[prop]
}
})
return this.push(column)
}
})
Object.defineProperty(this.rows, 'add', {
value () {
return this.push(Array.prototype.slice.call(arguments))
}
}
)
Object.defineProperty(this.rows, 'clear', {
value () {
return this.splice(0, this.length)
}
}
)
}
/*
@private
*/
Table.prototype._makeBulk = function _makeBulk () {
for (let i = 0; i < this.columns.length; i++) {
const col = this.columns[i]
switch (col.type) {
case TYPES.Date:
case TYPES.DateTime:
case TYPES.DateTime2:
for (let j = 0; j < this.rows.length; j++) {
const dateValue = this.rows[j][i]
if (typeof dateValue === 'string' || typeof dateValue === 'number') {
const date = new Date(dateValue)
if (isNaN(date.getDate())) {
throw new TypeError('Invalid date value passed to bulk rows')
}
this.rows[j][i] = date
}
}
break
case TYPES.Xml:
col.type = TYPES.NVarChar(MAX).type
break
case TYPES.UDT:
case TYPES.Geography:
case TYPES.Geometry:
col.type = TYPES.VarBinary(MAX).type
break
default:
break
}
}
return this
}
Table.prototype.declare = function declare () {
const pkey = this.columns.filter(col => col.primary === true).map(col => `[${col.name}]`)
const cols = this.columns.map(col => {
const def = [`[${col.name}] ${declareType(col.type, col)}`]
if (col.nullable === true) {
def.push('null')
} else if (col.nullable === false) {
def.push('not null')
}
if (col.primary === true && pkey.length === 1) {
def.push('primary key')
}
return def.join(' ')
})
const constraint = pkey.length > 1 ? `, constraint [PK_${this.temporary ? this.name.substr(1) : this.name}] primary key (${pkey.join(', ')})` : ''
return `create table ${this.path} (${cols.join(', ')}${constraint})`
}
Table.fromRecordset = function fromRecordset (recordset, name) {
const t = new this(name)
for (const colName in recordset.columns) {
if (objectHasProperty(recordset.columns, colName)) {
const col = recordset.columns[colName]
t.columns.add(colName, {
type: col.type,
length: col.length,
scale: col.scale,
precision: col.precision
}, {
nullable: col.nullable,
identity: col.identity,
readOnly: col.readOnly
})
}
}
if (t.columns.length === 1 && t.columns[0].name === JSON_COLUMN_ID) {
for (let i = 0; i < recordset.length; i++) {
t.rows.add(JSON.stringify(recordset[i]))
}
} else {
for (let i = 0; i < recordset.length; i++) {
t.rows.add.apply(t.rows, t.columns.map(col => recordset[i][col.name]))
}
}
return t
}
Table.parseName = function parseName (name) {
const length = name.length
let cursor = -1
let buffer = ''
let escaped = false
const path = []
while (++cursor < length) {
const char = name.charAt(cursor)
if (char === '[') {
if (escaped) {
buffer += char
} else {
escaped = true
}
} else if (char === ']') {
if (escaped) {
escaped = false
} else {
throw new Error('Invalid table name.')
}
} else if (char === '.') {
if (escaped) {
buffer += char
} else {
path.push(buffer)
buffer = ''
}
} else {
buffer += char
}
}
if (buffer) {
path.push(buffer)
}
switch (path.length) {
case 1:
return {
name: path[0],
schema: null,
database: null
}
case 2:
return {
name: path[1],
schema: path[0],
database: null
}
case 3:
return {
name: path[2],
schema: path[1],
database: path[0]
}
default:
throw new Error('Invalid table name.')
}
}
module.exports = Table

View File

@ -0,0 +1,188 @@
'use strict'
const tds = require('tedious')
const debug = require('debug')('mssql:tedi')
const BaseConnectionPool = require('../base/connection-pool')
const { IDS } = require('../utils')
const shared = require('../shared')
const ConnectionError = require('../error/connection-error')
const { CHANNELS, publish } = require('../diagnostics')
class ConnectionPool extends BaseConnectionPool {
_config () {
const cfg = {
server: this.config.server,
options: Object.assign({
encrypt: typeof this.config.encrypt === 'boolean' ? this.config.encrypt : true,
trustServerCertificate: typeof this.config.trustServerCertificate === 'boolean' ? this.config.trustServerCertificate : false
}, this.config.options),
authentication: Object.assign({
type: this.config.domain !== undefined ? 'ntlm' : this.config.authentication_type !== undefined ? this.config.authentication_type : 'default',
options: Object.entries({
userName: this.config.user,
password: this.config.password,
domain: this.config.domain,
clientId: this.config.clientId,
clientSecret: this.config.clientSecret,
tenantId: this.config.tenantId,
token: this.config.token,
msiEndpoint: this.config.msiEndpoint,
msiSecret: this.config.msiSecret
}).reduce((acc, [key, val]) => {
if (typeof val !== 'undefined') {
return { ...acc, [key]: val }
}
return acc
}, {})
}, this.config.authentication)
}
cfg.options.database = cfg.options.database || this.config.database
cfg.options.port = cfg.options.port || this.config.port
cfg.options.connectTimeout = cfg.options.connectTimeout ?? this.config.connectionTimeout ?? this.config.timeout ?? 15000
cfg.options.requestTimeout = cfg.options.requestTimeout ?? this.config.requestTimeout ?? this.config.timeout ?? 15000
cfg.options.tdsVersion = cfg.options.tdsVersion || '7_4'
cfg.options.rowCollectionOnDone = cfg.options.rowCollectionOnDone || false
cfg.options.rowCollectionOnRequestCompletion = cfg.options.rowCollectionOnRequestCompletion || false
cfg.options.useColumnNames = cfg.options.useColumnNames || false
cfg.options.appName = cfg.options.appName || 'node-mssql'
// tedious always connect via tcp when port is specified
if (cfg.options.instanceName) delete cfg.options.port
if (isNaN(cfg.options.requestTimeout)) cfg.options.requestTimeout = 15000
if (cfg.options.requestTimeout === Infinity || cfg.options.requestTimeout < 0) cfg.options.requestTimeout = 0
if (!cfg.options.debug && this.config.debug) {
cfg.options.debug = {
packet: true,
token: true,
data: true,
payload: true
}
}
return cfg
}
_poolCreate () {
return new shared.Promise((resolve, reject) => {
const resolveOnce = (v) => {
resolve(v)
resolve = reject = () => {}
}
const rejectOnce = (e) => {
reject(e)
resolve = reject = () => {}
}
let tedious
try {
tedious = new tds.Connection(this._config())
} catch (err) {
rejectOnce(err)
return
}
tedious.connect(err => {
if (err) {
err = new ConnectionError(err)
return rejectOnce(err)
}
debug('connection(%d): established', IDS.get(tedious))
this.collation = tedious.databaseCollation
publish(CHANNELS.CONNECTION_CREATE, () => ({
connectionId: IDS.get(tedious),
poolId: IDS.get(this),
server: this.config.server,
database: this.config.database
}))
resolveOnce(tedious)
})
IDS.add(tedious, 'Connection')
debug('pool(%d): connection #%d created', IDS.get(this), IDS.get(tedious))
debug('connection(%d): establishing', IDS.get(tedious))
tedious.on('end', () => {
const err = new ConnectionError('The connection ended without ever completing the connection')
rejectOnce(err)
})
tedious.on('error', err => {
if (err.code === 'ESOCKET') {
tedious.hasError = true
} else {
this.emit('error', err)
}
rejectOnce(err)
})
if (this.config.debug) {
tedious.on('debug', this.emit.bind(this, 'debug', tedious))
}
if (typeof this.config.beforeConnect === 'function') {
this.config.beforeConnect(tedious)
}
})
}
_poolValidate (tedious) {
if (!tedious || tedious.closed || tedious.hasError) {
return false
}
const mode = this.config.validateConnection
if (!mode) {
return true
}
// Socket-level validation: check connection state and socket health
// without executing a SQL query. Much cheaper than SELECT 1 at scale.
if (mode === 'socket') {
if (tedious.state !== tedious.STATE.LOGGED_IN) {
return false
}
if (!tedious.socket || tedious.socket.destroyed || !tedious.socket.writable) {
return false
}
return true
}
// SQL-level validation (default): execute SELECT 1 to verify the
// connection is fully functional end-to-end.
return new shared.Promise((resolve) => {
const req = new tds.Request('SELECT 1;', (err) => {
resolve(!err)
})
tedious.execSql(req)
})
}
_poolDestroy (tedious) {
return new shared.Promise((resolve, reject) => {
if (!tedious) {
resolve()
return
}
debug('connection(%d): destroying', IDS.get(tedious))
const connectionId = IDS.get(tedious)
const poolId = IDS.get(this)
if (tedious.closed) {
debug('connection(%d): already closed', IDS.get(tedious))
resolve()
} else {
tedious.once('end', () => {
debug('connection(%d): destroyed', IDS.get(tedious))
publish(CHANNELS.CONNECTION_DESTROY, () => ({
connectionId,
poolId
}))
resolve()
})
tedious.close()
}
})
}
}
module.exports = ConnectionPool

35
backend/node_modules/mssql/lib/tedious/index.js generated vendored Normal file
View File

@ -0,0 +1,35 @@
'use strict'
const base = require('../base')
const ConnectionPool = require('./connection-pool')
const Transaction = require('./transaction')
const Request = require('./request')
module.exports = Object.assign({
ConnectionPool,
Transaction,
Request,
PreparedStatement: base.PreparedStatement
}, base.exports)
Object.defineProperty(module.exports, 'Promise', {
enumerable: true,
get: () => {
return base.Promise
},
set: (value) => {
base.Promise = value
}
})
Object.defineProperty(module.exports, 'valueHandler', {
enumerable: true,
value: base.valueHandler,
writable: false,
configurable: false
})
base.driver.name = 'tedious'
base.driver.ConnectionPool = ConnectionPool
base.driver.Transaction = Transaction
base.driver.Request = Request

1071
backend/node_modules/mssql/lib/tedious/request.js generated vendored Normal file

File diff suppressed because it is too large Load Diff

104
backend/node_modules/mssql/lib/tedious/transaction.js generated vendored Normal file
View File

@ -0,0 +1,104 @@
'use strict'
const debug = require('debug')('mssql:tedi')
const BaseTransaction = require('../base/transaction')
const { IDS } = require('../utils')
const TransactionError = require('../error/transaction-error')
const { CHANNELS, publish } = require('../diagnostics')
class Transaction extends BaseTransaction {
constructor (parent, overrides) {
super(parent, overrides)
this._abort = () => {
if (!this._rollbackRequested) {
// transaction interrupted because of XACT_ABORT
const pc = this._acquiredConnection
// defer releasing so connection can switch from SentClientRequest to LoggedIn state
setImmediate(this.parent.release.bind(this.parent), pc)
this._acquiredConnection.removeListener('rollbackTransaction', this._abort)
this._acquiredConnection = null
this._acquiredConfig = null
this._aborted = true
this._abortReason = this._abortReason || new Error('Transaction was rolled back by the server')
publish(CHANNELS.TRANSACTION_ROLLBACK, () => ({
transactionId: IDS.get(this),
aborted: true
}))
this.emit('rollback', true)
}
}
}
_begin (isolationLevel, callback) {
super._begin(isolationLevel, err => {
if (err) return callback(err)
debug('transaction(%d): begin', IDS.get(this))
this.parent.acquire(this, (err, connection, config) => {
if (err) return callback(err)
this._acquiredConnection = connection
this._acquiredConnection.on('rollbackTransaction', this._abort)
this._acquiredConfig = config
connection.beginTransaction(err => {
if (err) err = new TransactionError(err)
debug('transaction(%d): begun', IDS.get(this))
callback(err)
}, this.name, this.isolationLevel)
})
})
}
_commit (callback) {
super._commit(err => {
if (err) return callback(err)
debug('transaction(%d): commit', IDS.get(this))
this._acquiredConnection.commitTransaction(err => {
if (err) err = new TransactionError(err)
this._acquiredConnection.removeListener('rollbackTransaction', this._abort)
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
if (!err) debug('transaction(%d): commited', IDS.get(this))
callback(err)
})
})
}
_rollback (callback) {
super._rollback(err => {
if (err) return callback(err)
debug('transaction(%d): rollback', IDS.get(this))
this._acquiredConnection.rollbackTransaction(err => {
if (err) err = new TransactionError(err)
this._acquiredConnection.removeListener('rollbackTransaction', this._abort)
this.parent.release(this._acquiredConnection)
this._acquiredConnection = null
this._acquiredConfig = null
if (!err) debug('transaction(%d): rolled back', IDS.get(this))
callback(err)
})
})
}
}
module.exports = Transaction

322
backend/node_modules/mssql/lib/udt.js generated vendored Normal file
View File

@ -0,0 +1,322 @@
'use strict'
/* const FIGURE = {
INTERIOR_RING: 0x00,
STROKE: 0x01,
EXTERIOR_RING: 0x02
};
const FIGURE_V2 = {
POINT: 0x00,
LINE: 0x01,
ARC: 0x02,
COMPOSITE_CURVE: 0x03
};
const SHAPE = {
POINT: 0x01,
LINESTRING: 0x02,
POLYGON: 0x03,
MULTIPOINT: 0x04,
MULTILINESTRING: 0x05,
MULTIPOLYGON: 0x06,
GEOMETRY_COLLECTION: 0x07
};
const SHAPE_V2 = {
POINT: 0x01,
LINESTRING: 0x02,
POLYGON: 0x03,
MULTIPOINT: 0x04,
MULTILINESTRING: 0x05,
MULTIPOLYGON: 0x06,
GEOMETRY_COLLECTION: 0x07,
CIRCULAR_STRING: 0x08,
COMPOUND_CURVE: 0x09,
CURVE_POLYGON: 0x0A,
FULL_GLOBE: 0x0B
};
const SEGMENT = {
LINE: 0x00,
ARC: 0x01,
FIRST_LINE: 0x02,
FIRST_ARC: 0x03
}; */
const ensureBytes = (buffer, needed) => {
if (buffer.position + needed > buffer.length) {
throw new Error(`Corrupt or truncated spatial data: expected ${needed} bytes at position ${buffer.position}, but only ${buffer.length - buffer.position} bytes remain`)
}
}
class Point {
constructor () {
this.x = 0
this.y = 0
this.z = null
this.m = null
}
}
const parsePoints = (buffer, count, isGeometryPoint) => {
// s2.1.5 + s2.1.6
// The key distinction for parsing is that a GEOGRAPHY POINT is ordered Lat (y) then Long (x),
// while a GEOMETRY POINT is ordered x then y.
// Further, there are additional range constraints on GEOGRAPHY POINT that are useful for testing that the coordinate order has not been flipped, such as that Lat must be in the range [-90, +90].
const points = []
if (count < 1) {
return points
}
ensureBytes(buffer, count * 16)
if (isGeometryPoint) {
// GEOMETRY POINT (s2.1.6): x then y.
for (let i = 1; i <= count; i++) {
const point = new Point()
points.push(point)
point.x = buffer.readDoubleLE(buffer.position)
point.y = buffer.readDoubleLE(buffer.position + 8)
buffer.position += 16
}
} else {
// GEOGRAPHY POINT (s2.1.5): Lat (y) then Long (x).
for (let i = 1; i <= count; i++) {
const point = new Point()
points.push(point)
point.lat = buffer.readDoubleLE(buffer.position)
point.lng = buffer.readDoubleLE(buffer.position + 8)
// For backwards compatibility, preserve the coordinate inversion in x and y.
// A future breaking change likely eliminate x and y for geography points in favor of just the lat and lng fields, as they've proven marvelously confusing.
// See discussion at: https://github.com/tediousjs/node-mssql/pull/1282#discussion_r677769531
point.x = point.lat
point.y = point.lng
buffer.position += 16
}
}
return points
}
const parseZ = (buffer, points) => {
// s2.1.1 + s.2.1.2
if (points < 1) {
return
}
ensureBytes(buffer, points.length * 8)
points.forEach(point => {
point.z = buffer.readDoubleLE(buffer.position)
buffer.position += 8
})
}
const parseM = (buffer, points) => {
// s2.1.1 + s.2.1.2
if (points < 1) {
return
}
ensureBytes(buffer, points.length * 8)
points.forEach(point => {
point.m = buffer.readDoubleLE(buffer.position)
buffer.position += 8
})
}
const parseFigures = (buffer, count, properties) => {
// s2.1.3
const figures = []
if (count < 1) {
return figures
}
if (properties.P) {
figures.push({
attribute: 0x01,
pointOffset: 0
})
} else if (properties.L) {
figures.push({
attribute: 0x01,
pointOffset: 0
})
} else {
ensureBytes(buffer, count * 5)
for (let i = 1; i <= count; i++) {
figures.push({
attribute: buffer.readUInt8(buffer.position),
pointOffset: buffer.readInt32LE(buffer.position + 1)
})
buffer.position += 5
}
}
return figures
}
const parseShapes = (buffer, count, properties) => {
// s2.1.4
const shapes = []
if (count < 1) {
return shapes
}
if (properties.P) {
shapes.push({
parentOffset: -1,
figureOffset: 0,
type: 0x01
})
} else if (properties.L) {
shapes.push({
parentOffset: -1,
figureOffset: 0,
type: 0x02
})
} else {
ensureBytes(buffer, count * 9)
for (let i = 1; i <= count; i++) {
shapes.push({
parentOffset: buffer.readInt32LE(buffer.position),
figureOffset: buffer.readInt32LE(buffer.position + 4),
type: buffer.readUInt8(buffer.position + 8)
})
buffer.position += 9
}
}
return shapes
}
const parseSegments = (buffer, count) => {
// s2.1.7
const segments = []
if (count < 1) {
return segments
}
ensureBytes(buffer, count)
for (let i = 1; i <= count; i++) {
segments.push({ type: buffer.readUInt8(buffer.position) })
buffer.position++
}
return segments
}
const parseGeography = (buffer, isUsingGeometryPoints) => {
// s2.1.1 + s.2.1.2
ensureBytes(buffer, 6)
const srid = buffer.readInt32LE(0)
if (srid === -1) {
return null
}
const value = {
srid,
version: buffer.readUInt8(4)
}
const flags = buffer.readUInt8(5)
buffer.position = 6
const properties = {
Z: (flags & (1 << 0)) > 0,
M: (flags & (1 << 1)) > 0,
V: (flags & (1 << 2)) > 0,
P: (flags & (1 << 3)) > 0,
L: (flags & (1 << 4)) > 0
}
if (value.version === 2) {
properties.H = (flags & (1 << 5)) > 0
}
let numberOfPoints
if (properties.P) {
numberOfPoints = 1
} else if (properties.L) {
numberOfPoints = 2
} else {
ensureBytes(buffer, 4)
numberOfPoints = buffer.readUInt32LE(buffer.position)
buffer.position += 4
}
value.points = parsePoints(buffer, numberOfPoints, isUsingGeometryPoints)
if (properties.Z) {
parseZ(buffer, value.points)
}
if (properties.M) {
parseM(buffer, value.points)
}
let numberOfFigures
if (properties.P) {
numberOfFigures = 1
} else if (properties.L) {
numberOfFigures = 1
} else {
ensureBytes(buffer, 4)
numberOfFigures = buffer.readUInt32LE(buffer.position)
buffer.position += 4
}
value.figures = parseFigures(buffer, numberOfFigures, properties)
let numberOfShapes
if (properties.P) {
numberOfShapes = 1
} else if (properties.L) {
numberOfShapes = 1
} else {
ensureBytes(buffer, 4)
numberOfShapes = buffer.readUInt32LE(buffer.position)
buffer.position += 4
}
value.shapes = parseShapes(buffer, numberOfShapes, properties)
if (value.version === 2 && buffer.position + 4 <= buffer.length) {
const numberOfSegments = buffer.readUInt32LE(buffer.position)
buffer.position += 4
value.segments = parseSegments(buffer, numberOfSegments)
} else {
value.segments = []
}
return value
}
module.exports.PARSERS = {
geography (buffer) {
return parseGeography(buffer, /* isUsingGeometryPoints: */false)
},
geometry (buffer) {
return parseGeography(buffer, /* isUsingGeometryPoints: */true)
}
}

31
backend/node_modules/mssql/lib/utils.js generated vendored Normal file
View File

@ -0,0 +1,31 @@
'use strict'
const IDS = new WeakMap()
const INCREMENT = {
Connection: 1,
ConnectionPool: 1,
Request: 1,
Transaction: 1,
PreparedStatement: 1
}
const getPoolId = (obj) => {
let parent = obj && obj.parent
while (parent && !parent.pool) {
parent = parent.parent
}
return parent ? IDS.get(parent) : undefined
}
module.exports = {
objectHasProperty: (object, property) => Object.prototype.hasOwnProperty.call(object, property),
INCREMENT,
IDS: {
get: IDS.get.bind(IDS),
add: (object, type, id) => {
if (id) return IDS.set(object, id)
IDS.set(object, INCREMENT[type]++)
}
},
getPoolId
}

3
backend/node_modules/mssql/msnodesqlv8.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
'use strict'
module.exports = require('./lib/msnodesqlv8')

75
backend/node_modules/mssql/package.json generated vendored Normal file
View File

@ -0,0 +1,75 @@
{
"author": {
"name": "Patrik Simek",
"url": "https://patriksimek.cz"
},
"name": "mssql",
"description": "Microsoft SQL Server client for Node.js.",
"keywords": [
"database",
"mssql",
"sql",
"server",
"msnodesql",
"sqlserver",
"tds",
"node-tds",
"tedious",
"node-sqlserver",
"sqlserver",
"msnodesqlv8",
"azure",
"node-mssql"
],
"version": "12.5.5",
"main": "index.js",
"type": "commonjs",
"repository": {
"type": "git",
"url": "git+https://github.com/tediousjs/node-mssql.git"
},
"homepage": "https://github.com/tediousjs/node-mssql#readme",
"bugs": {
"url": "https://github.com/tediousjs/node-mssql/issues"
},
"license": "MIT",
"dependencies": {
"@tediousjs/connection-string": "^1.0.0",
"commander": "^11.0.0",
"debug": "^4.3.3",
"tarn": "^3.0.2",
"tedious": "^19.0.0"
},
"devDependencies": {
"@commitlint/cli": "^20.0.0",
"@commitlint/config-conventional": "^20.0.0",
"@semantic-release/commit-analyzer": "^13.0.1",
"@semantic-release/github": "^12.0.6",
"@semantic-release/npm": "^13.1.5",
"@semantic-release/release-notes-generator": "^14.1.0",
"mocha": "^11.0.1",
"semantic-release": "^25.0.3",
"standard": "^17.0.0"
},
"engines": {
"node": ">=18.19.0"
},
"files": [
"lib/",
"bin/",
"tedious.js",
"msnodesqlv8.js"
],
"scripts": {
"commitlint": "commitlint --from origin/master --to HEAD",
"test": "npm run lint && npm run test-unit",
"lint": "standard",
"test-unit": "mocha --exit -t 15000 test/common/unit.js",
"test-tedious": "mocha --exit -t 15000 test/tedious",
"test-msnodesqlv8": "mocha --exit -t 30000 test/msnodesqlv8",
"test-cli": "mocha --exit -t 15000 test/common/cli.js"
},
"bin": {
"mssql": "bin/mssql"
}
}

3
backend/node_modules/mssql/tedious.js generated vendored Normal file
View File

@ -0,0 +1,3 @@
'use strict'
module.exports = require('./lib/tedious')