@sap/cds 1.15.1 → 1.18.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/{developer-license-3.1.txt → LICENSE} +37 -35
- package/_hdbext/README.md +373 -0
- package/_hdbext/index.js +4 -0
- package/_hdbext/lib/client-factory.js +62 -0
- package/_hdbext/lib/client-session.js +96 -0
- package/_hdbext/lib/conn-options.js +84 -0
- package/_hdbext/lib/constants.js +79 -0
- package/_hdbext/lib/internal-constants.js +7 -0
- package/_hdbext/lib/middleware.js +46 -0
- package/_hdbext/lib/pool.js +236 -0
- package/_hdbext/lib/safe-sql.js +17 -0
- package/_hdbext/lib/sql-injection-utils.js +149 -0
- package/cds-queries-geo.js +347 -371
- package/cds-queries.js +2692 -2229
- package/cds.js +111 -104
- package/exprs.js +118 -107
- package/manager.js +696 -614
- package/metadata.js +604 -542
- package/npm-shrinkwrap.json +268 -0
- package/package.json +40 -1
- package/transaction.js +45 -51
- package/util/Queue.js +32 -30
- package/utils.js +182 -159
- package/xsjs-cds.js +231 -221
- package/.project +0 -11
- package/SIGNATURE.SMF +0 -1747
- package/TUTORIAL.md +0 -1236
- package/dependencies +0 -56
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('lodash');
|
|
4
|
+
var async = require('async');
|
|
5
|
+
var util = require('util');
|
|
6
|
+
var constants = require('./constants');
|
|
7
|
+
var debug = require('debug')('hdbext:client-session');
|
|
8
|
+
var safeSql = require('./safe-sql');
|
|
9
|
+
|
|
10
|
+
exports.setSchema = setSchema;
|
|
11
|
+
exports.getSchema = getSchema;
|
|
12
|
+
exports.setLocale = setLocale;
|
|
13
|
+
exports.setIsolationLevel = setIsolationLevel;
|
|
14
|
+
exports.updateConnectionOptions = updateConnectionOptions;
|
|
15
|
+
exports.unsetSessionVariables = unsetSessionVariables;
|
|
16
|
+
|
|
17
|
+
function setSchema(client, schema, cb) {
|
|
18
|
+
if (typeof schema !== 'string') {
|
|
19
|
+
return cb(new Error('Schema name must be a string'));
|
|
20
|
+
}
|
|
21
|
+
var sql = 'SET SCHEMA ' + safeSql.identifier(schema);
|
|
22
|
+
debug('Setting schema: %s', sql);
|
|
23
|
+
client.exec(sql, cb);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getSchema(client, cb) {
|
|
27
|
+
client.exec('SELECT CURRENT_SCHEMA FROM DUMMY', function (err, rs) {
|
|
28
|
+
if (err) {
|
|
29
|
+
return cb(err);
|
|
30
|
+
}
|
|
31
|
+
return cb(null, rs[0].CURRENT_SCHEMA);
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function setLocale(client, locale, cb) {
|
|
36
|
+
client._connection.getClientInfo().setProperty('LOCALE', locale);
|
|
37
|
+
cb();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function setSessionVariable(client, key, value, cb) {
|
|
41
|
+
if (_.isNil(value)) {
|
|
42
|
+
return cb();
|
|
43
|
+
}
|
|
44
|
+
var sql = util.format('SET %s = %s', safeSql.stringLiteral(key), safeSql.stringLiteral(value));
|
|
45
|
+
client.exec(sql, cb);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function unsetSessionVariable(client, key, cb) {
|
|
49
|
+
var sql = 'UNSET ' + safeSql.stringLiteral(key);
|
|
50
|
+
client.exec(sql, cb);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function setIsolationLevel(client, isolationLevel, cb) {
|
|
54
|
+
var level = constants.isolationLevelValues[isolationLevel];
|
|
55
|
+
if (typeof level !== 'string') {
|
|
56
|
+
return cb(new Error('Invalid isolation level: ' + isolationLevel));
|
|
57
|
+
}
|
|
58
|
+
client.exec('SET TRANSACTION ISOLATION LEVEL ' + level, cb);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function setSessionVariables(client, vars, cb) {
|
|
62
|
+
if (!vars) {
|
|
63
|
+
return cb();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async.each(Object.keys(vars), function (key, callback) {
|
|
67
|
+
setSessionVariable(client, key, vars[key], callback);
|
|
68
|
+
}, cb);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function unsetSessionVariables(client, vars, cb) {
|
|
72
|
+
if (!vars) {
|
|
73
|
+
return cb();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
async.each(Object.keys(vars), function (key, callback) {
|
|
77
|
+
unsetSessionVariable(client, key, callback);
|
|
78
|
+
}, cb);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function updateConnectionOptions(client, options, callback) {
|
|
82
|
+
if (!_.isNil(options.autoCommit)) {
|
|
83
|
+
client.setAutoCommit(Boolean(options.autoCommit));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async.parallel([function (cb) {
|
|
87
|
+
options.schema ? setSchema(client, options.schema, cb) : cb();
|
|
88
|
+
}, function (cb) {
|
|
89
|
+
options.session ? setSessionVariables(client, options.session, cb) : cb();
|
|
90
|
+
}, function (cb) {
|
|
91
|
+
options.locale ? setLocale(client, options.locale.replace(/-/g, '_'), cb) : cb();
|
|
92
|
+
}, function (cb) {
|
|
93
|
+
options.isolationLevel ? setIsolationLevel(client, options.isolationLevel, cb) : cb();
|
|
94
|
+
}], callback);
|
|
95
|
+
}
|
|
96
|
+
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var AcceptLanguageParser = require('accept-language');
|
|
4
|
+
var fs = require('fs');
|
|
5
|
+
var os = require('os');
|
|
6
|
+
var SAPPassport = require('@sap/e2e-trace').Passport;
|
|
7
|
+
var internalConsts = require('./internal-constants');
|
|
8
|
+
var debug = require('debug')('hdbext:conn-options');
|
|
9
|
+
|
|
10
|
+
exports.getGlobalOptions = getGlobalOptions;
|
|
11
|
+
exports.getRequestOptions = getRequestOptions;
|
|
12
|
+
|
|
13
|
+
function getRequestOptions(req) {
|
|
14
|
+
var opt = { session: {} };
|
|
15
|
+
|
|
16
|
+
var authInfo = req.authInfo;
|
|
17
|
+
|
|
18
|
+
if (authInfo && authInfo.getGrantType && authInfo.getGrantType() !== internalConsts.GRANTTYPE_CLIENTCREDENTIAL) {
|
|
19
|
+
if (authInfo.getHdbToken) {
|
|
20
|
+
opt.session.XS_APPLICATIONUSER = authInfo.getHdbToken();
|
|
21
|
+
} else if (authInfo.getToken) {
|
|
22
|
+
opt.session.XS_APPLICATIONUSER = authInfo.getToken(internalConsts.SYSTEM, internalConsts.HDB);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (req.headers[SAPPassport.HEADER_NAME]) {
|
|
27
|
+
var passport = new SAPPassport(req.headers[SAPPassport.HEADER_NAME]);
|
|
28
|
+
passport.update({
|
|
29
|
+
connectionID: '00000000000000000000000000000000',
|
|
30
|
+
connectionCounter: 0
|
|
31
|
+
});
|
|
32
|
+
passport.compact();
|
|
33
|
+
opt.session.SAP_PASSPORT = passport.serialize();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
opt.locale = resolveRequestLanguage(req);
|
|
37
|
+
|
|
38
|
+
return opt;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function resolveRequestLanguage(req) {
|
|
42
|
+
var sapLang = req.headers['x-sap-request-language'];
|
|
43
|
+
if (sapLang) {
|
|
44
|
+
return sapLang;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
var acceptLanguage = req.headers['accept-language'];
|
|
48
|
+
if (acceptLanguage) {
|
|
49
|
+
var languagesByPreference = AcceptLanguageParser.parse(acceptLanguage);
|
|
50
|
+
if (languagesByPreference.length) {
|
|
51
|
+
return languagesByPreference[0].value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function getGlobalOptions() {
|
|
57
|
+
return {
|
|
58
|
+
session: {
|
|
59
|
+
APPLICATION: getApplicationName(),
|
|
60
|
+
APPLICATIONVERSION: getApplicationVersion()
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function getApplicationName() {
|
|
66
|
+
if (process.env.VCAP_APPLICATION) {
|
|
67
|
+
var app = JSON.parse(process.env.VCAP_APPLICATION);
|
|
68
|
+
var components = [app.application_name, app.space_name, app.organization_name]
|
|
69
|
+
.filter(Boolean);
|
|
70
|
+
if (components.length > 0) {
|
|
71
|
+
return components.join('/');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return process.pid + '@' + os.hostname();
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getApplicationVersion() {
|
|
78
|
+
try {
|
|
79
|
+
var pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8'));
|
|
80
|
+
return pkg.name + '@' + pkg.version;
|
|
81
|
+
} catch (err) {
|
|
82
|
+
debug(err);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// From SAP HANA SQL Command Network Protocol Reference, 2.6 Type Codes
|
|
4
|
+
exports.types = {
|
|
5
|
+
TINYINT: 1,
|
|
6
|
+
SMALLINT: 2,
|
|
7
|
+
INT: 3,
|
|
8
|
+
INTEGER: 3,
|
|
9
|
+
BIGINT: 4,
|
|
10
|
+
DECIMAL: 5,
|
|
11
|
+
REAL: 6,
|
|
12
|
+
DOUBLE: 7,
|
|
13
|
+
CHAR: 8,
|
|
14
|
+
VARCHAR: 9,
|
|
15
|
+
NCHAR: 10,
|
|
16
|
+
NVARCHAR: 11,
|
|
17
|
+
BINARY: 12,
|
|
18
|
+
VARBINARY: 13,
|
|
19
|
+
DATE: 14,
|
|
20
|
+
TIME: 15,
|
|
21
|
+
TIMESTAMP: 16,
|
|
22
|
+
CLOB: 25,
|
|
23
|
+
NCLOB: 26,
|
|
24
|
+
BLOB: 27,
|
|
25
|
+
BOOLEAN: 28,
|
|
26
|
+
STRING: 29,
|
|
27
|
+
NSTRING: 30,
|
|
28
|
+
BLOCATOR: 31,
|
|
29
|
+
NLOCATOR: 32,
|
|
30
|
+
BSTRING: 33,
|
|
31
|
+
TABLE: 45,
|
|
32
|
+
SMALLDECIMAL: 47,
|
|
33
|
+
ABAPITAB: 48,
|
|
34
|
+
ABAPSTRUCT: 49,
|
|
35
|
+
ARRAY: 50,
|
|
36
|
+
TEXT: 51,
|
|
37
|
+
SHORTTEXT: 52,
|
|
38
|
+
ALPHANUM: 55,
|
|
39
|
+
LONGDATE: 61,
|
|
40
|
+
SECONDDATE: 62,
|
|
41
|
+
DAYDATE: 63,
|
|
42
|
+
SECONDTIME: 64
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
exports.typeKeys = invert(exports.types);
|
|
46
|
+
|
|
47
|
+
exports.isolation = {
|
|
48
|
+
/**
|
|
49
|
+
* @type {number}
|
|
50
|
+
* @constant
|
|
51
|
+
*/
|
|
52
|
+
READ_COMMITTED: 2,
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @type {number}
|
|
56
|
+
* @constant
|
|
57
|
+
*/
|
|
58
|
+
REPEATABLE_READ: 4,
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @type {number}
|
|
62
|
+
* @constant
|
|
63
|
+
*/
|
|
64
|
+
SERIALIZABLE: 8
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
exports.isolationLevelValues = {
|
|
68
|
+
2: 'READ COMMITTED',
|
|
69
|
+
4: 'REPEATABLE READ',
|
|
70
|
+
8: 'SERIALIZABLE'
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function invert(source) {
|
|
74
|
+
var target = {};
|
|
75
|
+
for (var key in source) {
|
|
76
|
+
target[source[key]] = key;
|
|
77
|
+
}
|
|
78
|
+
return target;
|
|
79
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('lodash');
|
|
4
|
+
var debug = require('debug')('hdbext:middleware');
|
|
5
|
+
var poolModule = require('./pool');
|
|
6
|
+
var connOptions = require('./conn-options');
|
|
7
|
+
|
|
8
|
+
exports.middleware = function middleware(hanaService, poolOptions) {
|
|
9
|
+
var hanaOptions = _.merge({}, connOptions.getGlobalOptions(), hanaService);
|
|
10
|
+
var pool = poolModule.getPool(hanaOptions, poolOptions);
|
|
11
|
+
|
|
12
|
+
return function db(req, res, next) {
|
|
13
|
+
var opt = connOptions.getRequestOptions(req);
|
|
14
|
+
pool.acquire(opt, function (err, client) {
|
|
15
|
+
if (err) {
|
|
16
|
+
err.status = 500;
|
|
17
|
+
return next(err);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var releaseClient = true;
|
|
21
|
+
client.once('release', function () {
|
|
22
|
+
releaseClient = false;
|
|
23
|
+
delete req.db;
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
function cleanup() {
|
|
27
|
+
debug('Cleanup triggered');
|
|
28
|
+
delete req.db;
|
|
29
|
+
if (releaseClient) {
|
|
30
|
+
releaseClient = false;
|
|
31
|
+
pool.release(client);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var end = res.end;
|
|
36
|
+
res.end = function () {
|
|
37
|
+
cleanup();
|
|
38
|
+
res.end = end;
|
|
39
|
+
res.end.apply(this, arguments);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
req.db = client;
|
|
43
|
+
next();
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var _ = require('lodash');
|
|
4
|
+
var async = require('async');
|
|
5
|
+
var crypto = require('crypto');
|
|
6
|
+
var util = require('util');
|
|
7
|
+
var constants = require('./constants');
|
|
8
|
+
var factory = require('./client-factory');
|
|
9
|
+
var clientSession = require('./client-session');
|
|
10
|
+
var debug = require('debug')('hdbext:pool');
|
|
11
|
+
var safeSql = require('./safe-sql');
|
|
12
|
+
|
|
13
|
+
var INSUFFICIENT_PRIVILEGE_ERROR_CODE = 258;
|
|
14
|
+
|
|
15
|
+
var poolModule = require('generic-pool');
|
|
16
|
+
var LRU = require('lru-cache'),
|
|
17
|
+
cache = LRU({
|
|
18
|
+
max: 10,
|
|
19
|
+
dispose: function (key, pool) {
|
|
20
|
+
_drainPool(pool);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
exports.getPool = getPool;
|
|
25
|
+
exports.createPool = createPool;
|
|
26
|
+
|
|
27
|
+
function createPool(hanaService, options) {
|
|
28
|
+
var pool = _createPool(hanaService, options);
|
|
29
|
+
return _getPoolObject(pool, hanaService);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getPool(hanaService, options) {
|
|
33
|
+
var key = hanaService.host + ':' + hanaService.port + ':' + hanaService.assertion + ':' + hanaService.user + ':' + hanaService.password;
|
|
34
|
+
key = crypto.createHash('sha256').update(key).digest('hex');
|
|
35
|
+
var pool = cache.get(key);
|
|
36
|
+
if (!pool) {
|
|
37
|
+
pool = _createPool(hanaService, options);
|
|
38
|
+
cache.set(key, pool);
|
|
39
|
+
}
|
|
40
|
+
return _getPoolObject(pool, hanaService);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function _getPoolObject(pool, hanaService) {
|
|
44
|
+
return {
|
|
45
|
+
pool: pool,
|
|
46
|
+
acquire: _acquireConnection.bind(null, pool, hanaService),
|
|
47
|
+
release: _releaseToPool.bind(null, pool),
|
|
48
|
+
drain: _drainPool.bind(null, pool)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function _releaseToPool(pool, safeClient) {
|
|
53
|
+
function handleError(err) {
|
|
54
|
+
// Currently the 'user' from the service binding does not have the privileges required to access the view with the list of temporary tables.
|
|
55
|
+
// Connection will be terminated in order not to be reused. Logging on level debug in order not to flood the logs.
|
|
56
|
+
// Corresponding privileges will be added to the user in the service binding.
|
|
57
|
+
var insufficientPriv = err.code === INSUFFICIENT_PRIVILEGE_ERROR_CODE ? 'Insufficient privileges' : '';
|
|
58
|
+
debug('Could not reset connection: ', insufficientPriv, err);
|
|
59
|
+
pool.destroy(client);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
var client = Object.getPrototypeOf(safeClient);
|
|
63
|
+
if (client === null) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (!client._connection.isIdle()) {
|
|
67
|
+
client._connection._queue.once('drain', _releaseToPool.bind(this, pool, safeClient));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
safeClient._connection = undefined;
|
|
72
|
+
safeClient.emit('release');
|
|
73
|
+
safeClient.removeAllListeners();
|
|
74
|
+
client.removeAllListeners();
|
|
75
|
+
Object.setPrototypeOf(safeClient, null);
|
|
76
|
+
|
|
77
|
+
async.series([
|
|
78
|
+
function (cb) {
|
|
79
|
+
client.rollback(cb);
|
|
80
|
+
},
|
|
81
|
+
function (cb) {
|
|
82
|
+
clientSession.unsetSessionVariables(client, client._connectionUpdatedSettings.session, cb);
|
|
83
|
+
},
|
|
84
|
+
function (cb) {
|
|
85
|
+
client._connectionUpdatedSettings.session = undefined;
|
|
86
|
+
client._connectionInitialSettings = _getDeltaDBSettings({}, {}, _.merge({}, client._connectionDefaultSettings, client._connectionInitialSettings, client._connectionUpdatedSettings));
|
|
87
|
+
client._connectionUpdatedSettings = undefined;
|
|
88
|
+
clientSession.updateConnectionOptions(client, client._connectionInitialSettings, cb);
|
|
89
|
+
}
|
|
90
|
+
], function (err) {
|
|
91
|
+
if (err) {
|
|
92
|
+
return handleError(err);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async.waterfall([
|
|
96
|
+
client.exec.bind(client, 'SELECT SCHEMA_NAME, TABLE_NAME, TEMPORARY_TABLE_TYPE FROM M_TEMPORARY_TABLES WHERE CONNECTION_ID = CURRENT_CONNECTION'),
|
|
97
|
+
function (rs, cb) {
|
|
98
|
+
var statements = rs.map(function (row) {
|
|
99
|
+
var operation = (row.TEMPORARY_TABLE_TYPE === 'GLOBAL') ? 'TRUNCATE' : 'DROP';
|
|
100
|
+
var table = util.format('%s.%s', safeSql.identifier(row.SCHEMA_NAME), safeSql.identifier(row.TABLE_NAME));
|
|
101
|
+
return util.format('%s TABLE %s', operation, table);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
async.each(statements, function (statement, eachCb) {
|
|
105
|
+
client.exec(statement, function (err) {
|
|
106
|
+
debug(statement, err);
|
|
107
|
+
eachCb(err);
|
|
108
|
+
});
|
|
109
|
+
}, cb);
|
|
110
|
+
},
|
|
111
|
+
function (cb) {
|
|
112
|
+
client.commit(cb);
|
|
113
|
+
}
|
|
114
|
+
], function (err) {
|
|
115
|
+
if (err) {
|
|
116
|
+
return handleError(err);
|
|
117
|
+
}
|
|
118
|
+
pool.release(client);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function _acquireConnection(pool, hanaService, options, callback) {
|
|
124
|
+
if (arguments.length === 3) {
|
|
125
|
+
callback = arguments[2];
|
|
126
|
+
options = {};
|
|
127
|
+
}
|
|
128
|
+
var _options = _.merge({}, hanaService, options);
|
|
129
|
+
pool.acquire(function (err, client) {
|
|
130
|
+
if (err) {
|
|
131
|
+
return callback(err);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
var safeClient = Object.create(client);
|
|
135
|
+
client.close = _releaseToPool.bind(null, pool, safeClient);
|
|
136
|
+
client.disconnect = _releaseToPool.bind(null, pool, safeClient);
|
|
137
|
+
client.on('close', pool.destroy.bind(null, client));
|
|
138
|
+
|
|
139
|
+
client._connectionUpdatedSettings = _getDeltaDBSettings(client._connectionDefaultSettings, client._connectionInitialSettings
|
|
140
|
+
, _.pick(_options,['session', 'autoCommit', 'locale', 'isolationLevel', 'schema']));
|
|
141
|
+
clientSession.updateConnectionOptions(client, client._connectionUpdatedSettings, function (err) {
|
|
142
|
+
callback(err, safeClient);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function _drainPool(pool) {
|
|
148
|
+
pool.drain(function () {
|
|
149
|
+
pool.destroyAllNow();
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function _createPool(hanaService, options) {
|
|
154
|
+
debug('Creating pool');
|
|
155
|
+
var defaultOptions = {
|
|
156
|
+
max: 100,
|
|
157
|
+
min: 0,
|
|
158
|
+
idleTimeoutMillis: 10000,
|
|
159
|
+
log: false,
|
|
160
|
+
refreshIdle: false
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
options = _.extend(defaultOptions, options);
|
|
164
|
+
|
|
165
|
+
var pool = poolModule.Pool({
|
|
166
|
+
name: 'hana',
|
|
167
|
+
create: function (callback) {
|
|
168
|
+
debug('Creating client in pool');
|
|
169
|
+
factory.openBaseConnection(hanaService, function (err, client) {
|
|
170
|
+
if (err) {
|
|
171
|
+
return callback(err);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
client._connectionDefaultSettings = {
|
|
175
|
+
autoCommit: true,
|
|
176
|
+
locale: client.connectOptions.clientLocale,
|
|
177
|
+
isolationLevel: constants.isolation['READ_COMMITTED']
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
client._connectionInitialSettings = {
|
|
181
|
+
autoCommit: _.isNil(options.autoCommit) ? client._connectionDefaultSettings.autoCommit : !!options.autoCommit,
|
|
182
|
+
locale: hanaService.locale || client._connectionDefaultSettings.clientLocale,
|
|
183
|
+
isolationLevel: hanaService.isolationLevel || client._connectionDefaultSettings.isolationLevel,
|
|
184
|
+
schema: hanaService.schema
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
clientSession.getSchema(client, function (err, schema) {
|
|
188
|
+
client._connectionDefaultSettings.schema = schema;
|
|
189
|
+
var updatedSettings = _getDeltaDBSettings(client._connectionDefaultSettings, client._connectionDefaultSettings, client._connectionInitialSettings);
|
|
190
|
+
clientSession.updateConnectionOptions(client, updatedSettings, function (err) {
|
|
191
|
+
if (err) {
|
|
192
|
+
client.close();
|
|
193
|
+
client = null;
|
|
194
|
+
}
|
|
195
|
+
callback(err, client);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
destroy: function (client) {
|
|
201
|
+
debug('Destroying client from pool');
|
|
202
|
+
client._connection.close();
|
|
203
|
+
},
|
|
204
|
+
validate: function (client) {
|
|
205
|
+
return client.readyState === 'connected';
|
|
206
|
+
},
|
|
207
|
+
max: options.max,
|
|
208
|
+
min: options.min,
|
|
209
|
+
idleTimeoutMillis: options.idleTimeoutMillis,
|
|
210
|
+
log: options.log,
|
|
211
|
+
refreshIdle: options.refreshIdle,
|
|
212
|
+
reapIntervalMillis: options.reapIntervalMillis,
|
|
213
|
+
returnToHead: options.returnToHead,
|
|
214
|
+
priorityRange: options.priorityRange
|
|
215
|
+
});
|
|
216
|
+
return pool;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
function _getDeltaDBSettings(def, init, curr) {
|
|
221
|
+
def = def || {};
|
|
222
|
+
init = init || {};
|
|
223
|
+
curr = curr || {};
|
|
224
|
+
var res = {};
|
|
225
|
+
_.union(_.keys(curr), _.keys(init)).forEach(function (key) {
|
|
226
|
+
if (curr[key] === undefined && init[key] !== def[key] && init[key] !== undefined) {
|
|
227
|
+
res[key] = def[key];
|
|
228
|
+
} else {
|
|
229
|
+
if (curr[key] !== init[key] && (init[key] !== undefined || def[key] !== curr[key])) {
|
|
230
|
+
res[key] = curr[key];
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
return res;
|
|
236
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var sqlInjectionUtils = require('./sql-injection-utils');
|
|
4
|
+
var format = require('util').format;
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
identifier: identifier,
|
|
8
|
+
stringLiteral: stringLiteral
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
function identifier(identifier) {
|
|
12
|
+
return format('"%s"', sqlInjectionUtils.escapeDoubleQuotes(identifier));
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function stringLiteral(literal) {
|
|
16
|
+
return format("'%s'", sqlInjectionUtils.escapeSingleQuotes(literal));
|
|
17
|
+
}
|