@142vip/data-source
Version:
通用型数据源,支持多种数据库、API、CSV等形式的数据源管理
1,663 lines (1,532 loc) • 857 kB
JavaScript
'use strict';
const aliyunApiGateway = require('aliyun-api-gateway');
const axios = require('axios');
const crypto = require('node:crypto');
const clickhouse = require('clickhouse');
const lodash = require('lodash');
const pg = require('pg');
const mongodb = require('mongodb');
const require$$0$3 = require('events');
const require$$0$2 = require('process');
const require$$0$6 = require('net');
const require$$1$3 = require('tls');
const require$$1$1 = require('timers');
const require$$2 = require('stream');
const require$$1 = require('buffer');
const require$$0 = require('iconv-lite');
const require$$0$1 = require('crypto');
const require$$0$4 = require('zlib');
const require$$1$2 = require('util');
const require$$0$5 = require('url');
const os = require('node:os');
const sqlServer = require('mssql');
const sync = require('csv-parse/sync');
const jsCharDet = require('jschardet');
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
const axios__default = /*#__PURE__*/_interopDefaultCompat(axios);
const crypto__default = /*#__PURE__*/_interopDefaultCompat(crypto);
const require$$0__default$3 = /*#__PURE__*/_interopDefaultCompat(require$$0$3);
const require$$0__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$0$2);
const require$$0__default$6 = /*#__PURE__*/_interopDefaultCompat(require$$0$6);
const require$$1__default$3 = /*#__PURE__*/_interopDefaultCompat(require$$1$3);
const require$$1__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$1$1);
const require$$2__default = /*#__PURE__*/_interopDefaultCompat(require$$2);
const require$$1__default = /*#__PURE__*/_interopDefaultCompat(require$$1);
const require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
const require$$0__default$1 = /*#__PURE__*/_interopDefaultCompat(require$$0$1);
const require$$0__default$4 = /*#__PURE__*/_interopDefaultCompat(require$$0$4);
const require$$1__default$2 = /*#__PURE__*/_interopDefaultCompat(require$$1$2);
const require$$0__default$5 = /*#__PURE__*/_interopDefaultCompat(require$$0$5);
const os__default = /*#__PURE__*/_interopDefaultCompat(os);
const sqlServer__default = /*#__PURE__*/_interopDefaultCompat(sqlServer);
const jsCharDet__default = /*#__PURE__*/_interopDefaultCompat(jsCharDet);
function testURL(url) {
return /(?:http|ftp|https):\/\/[\w\-]+(?:\.[\w\-]+)+(?:[\w\-.,@?^=%&:/~+#]*[\w\-@?^=%&/~+#])?/.test(url);
}
function checkPasswordIsNil(password) {
return isEmpty(password) ? { password: null } : { password: "******" };
}
function isEmpty(value) {
return value == null || value === "";
}
function handlerDataSourceConnectError(dataSourceName, error) {
let message = `${dataSourceName}\u6570\u636E\u6E90\uFF0C\u6267\u884C\u5931\u8D25`;
if (!isEmpty(error?.message)) {
message = JSON.stringify(error.message);
}
return { success: false, message };
}
const AliGateway_API_TIMEOUT = 3e4;
class VipAliGatewayApi {
/**
* 获取连接数据
*/
async getConnectionData(params) {
try {
const aliClient = new aliyunApiGateway.Client(params.appKey, params.appSecret);
const data = await aliClient[params.method](params.url, {
timeout: AliGateway_API_TIMEOUT,
data: params.bodyParams,
headers: params.headerParams
});
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipAliGatewayApi.name, error);
}
}
}
class VipHttpApi {
/**
* 获取连接数据
*/
async getConnectionData(options) {
const { data, status } = await axios__default(options);
if (status === 200) {
return data;
}
return { success: false };
}
}
const DEFAULT_DTABLE_API_URL = "https://oapi.dtable.cloud/v0";
const DEFAULT_MAX_RECORDS = 1e3;
class VipDTableApi {
vipHttpApi = new VipHttpApi();
/**
* 获取连接数据
*/
async getConnectionData(options) {
try {
const data = await this.getTableAllRecords(options);
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipDTableApi.name, error);
}
}
/**
* 并发获取所有记录,提高获取速度
* @param options
*/
async getConnectionDataByConcurrency(options) {
try {
const data = await this.getTableAllRecordsByConcurrency(options);
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipDTableApi.name, error);
}
}
/**
* 获取分页表总数量
* @private
*/
async getPaginationTotal(options) {
const apiConfig = this.getApiConfig(options, { page: 1, size: 5 });
const data = await this.vipHttpApi.getConnectionData(apiConfig);
return data.data?.total ?? 0;
}
/**
* 循环获取所有记录,同步获取
*/
async getTableAllRecords(options) {
const total = await this.getPaginationTotal(options);
const maxPageSize = this.getMaxPageSize(options.maxRecords);
const pageCount = Math.ceil(total / maxPageSize);
const allFields = [];
for (let page = 1; page <= pageCount; page++) {
const apiConfig = this.getApiConfig(options, { page, size: maxPageSize });
const data = await this.vipHttpApi.getConnectionData(apiConfig);
const currentFields = data.data?.records.map((record) => record.fields) ?? [];
allFields.push(...currentFields);
}
return allFields;
}
/**
* 并发获取所有记录,提高获取速度
*/
async getTableAllRecordsByConcurrency(options) {
const total = await this.getPaginationTotal(options);
const maxPageSize = this.getMaxPageSize(options.maxRecords);
const pageCount = Math.ceil(total / maxPageSize);
const promises = Array.from({ length: pageCount }, (_, index) => {
const page = index + 1;
const apiConfig = this.getApiConfig(options, { page, size: maxPageSize });
return this.vipHttpApi.getConnectionData(apiConfig).then((data) => data.data?.records.map((record) => record.fields) ?? []);
});
const allFlatFields = await Promise.all(promises);
return allFlatFields.flat();
}
/**
* 分页最大数量
* @private
*/
getMaxPageSize(maxRecords) {
if (maxRecords == null || maxRecords <= 0 || maxRecords > DEFAULT_MAX_RECORDS) {
return DEFAULT_MAX_RECORDS;
}
return maxRecords;
}
/**
* 获取请求配置
* @private
*/
getApiConfig(options, pageOptions) {
return {
url: `${DEFAULT_DTABLE_API_URL}/tables/${options.tableId}/records`,
method: "GET",
params: {
view_id: options.viewId,
page: pageOptions?.page ?? 1,
size: pageOptions?.size ?? 1e3
},
headers: {
Authorization: `Bearer ${options.apiKey}`
}
};
}
}
class VipDtStackApi {
/**
* 获取连接数据
*/
async getConnectionData(options) {
try {
const apiConfig = this.getConfig(options);
return new VipHttpApi().getConnectionData(apiConfig);
} catch (error) {
return handlerDataSourceConnectError(VipDtStackApi.name, error);
}
}
/**
* 获取数栈请求时配置
* @param apiParams
* @private
*/
getConfig(apiParams) {
const timestamp = (/* @__PURE__ */ new Date()).getDate().toString();
const signToStr = [
...Object.entries(apiParams.bodyParams),
...Object.entries(apiParams.headerParams),
...Object.entries(apiParams.queryParams),
["X-Auth-Key", apiParams.appKey],
["X-Auth-ActionId", apiParams.apiId],
["X-Auth-Timestamp", timestamp]
].sort().map(([key, value]) => {
return `${key}=${value}`;
}).concat(apiParams.appSecret).join("&");
const signature = this.getSignature(signToStr);
const baseUrl = new URL(apiParams.url);
baseUrl.pathname = apiParams.pathParams.replace(/^\//, "");
const apiUrl = baseUrl.toString();
return {
url: apiUrl,
method: apiParams.method,
// query参数
params: apiParams.queryParams,
// body参数
data: apiParams.bodyParams,
// timeout: APIDTSightConfig.API_TIMEOUT * 1000,
headers: {
...apiParams.headerParams,
"X-Auth-Key": apiParams.appKey,
"X-Auth-ActionId": apiParams.apiId,
"X-Auth-Signature": signature,
"X-Auth-Timestamp": timestamp
}
};
}
/**
* 字符串进行MD5加密
* - 数栈请求数据,加密获取签名
*/
getSignature(strToSign) {
return crypto__default.createHash("md5").update(strToSign, "utf8").digest("hex");
}
}
class VipClickhouse {
/**
* 获取连接数据
*/
async getConnectionData(options) {
try {
const ch = new clickhouse.ClickHouse({
url: options.host,
port: options.port,
basicAuth: {
username: options.username,
password: options.password
},
config: {
session_timeout: 60,
enable_http_compression: 0,
database: options.database
}
});
const data = await ch.query(options.querySql).toPromise();
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipClickhouse.name, error);
}
}
}
class VipDameng {
/**
* 获取连接数据
*/
async getConnectionData(options) {
const dmdb = require("dmdb");
let connection;
let dmPool;
try {
dmdb.fetchAsString = [dmdb.CLOB, dmdb.BUFFER];
dmdb.fetchAsBuffer = [dmdb.BLOB];
dmPool = await dmdb.createPool({
connectString: `dm://${options.username}:${options.password}@${options.host}:${options.port}`,
poolMax: 10,
poolMin: 1
});
connection = await dmPool.getConnection();
const result = await connection.execute(options.querySql, [], {
outFormat: dmdb.OUT_FORMAT_OBJECT
});
const data = result.rows?.map(
(item) => lodash.mapValues(item, (value) => typeof value === "bigint" ? value.toString() : value)
);
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipDameng.name, error);
} finally {
await dmPool?.close();
await connection?.close();
}
}
}
class VipIbmDB {
/**
* 获取连接数据
*/
async getConnectionData(options) {
const ibmDB = require("ibm_db");
let connection;
try {
connection = ibmDB();
const connectURL = this.getConnectURL(options);
await connection.open(connectURL);
} catch (error) {
return handlerDataSourceConnectError(VipIbmDB.name, error);
}
try {
const data = await connection.query(options.querySql);
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipIbmDB.name, error);
} finally {
await connection.close();
}
}
/**
* 获取链接URL
* @param options
* @private
*/
getConnectURL(options) {
return `DATABASE=${options.database};HOSTNAME=${options.host};PORT=${options.port};PROTOCOL=TCPIP;UID=${options.username};PWD=${options.password}`;
}
}
class VipKingBase {
/**
* 获取连接数据
*/
async getConnectionData(options) {
let connection;
try {
connection = new pg.Pool({
host: options.host,
port: options.port,
database: options.database,
user: options.username,
password: options.password
});
const queryResult = await connection.query(options.querySql);
const data = queryResult.rows != null ? queryResult.rows : [];
return { success: true, data };
} catch (error) {
return handlerDataSourceConnectError(VipKingBase.name, error);
} finally {
await connection?.end();
}
}
}
const MONGO_DEFAULT_TIMEOUT = 60 * 1e3;
class VipMongo {
/**
* 获取连接数据
*/
async getConnectionData(options) {
let client;
try {
client = await this.getMongoClient(options);
const mongoDB = client.db(options.database);
return await this.findTableData(mongoDB, options);
} catch (error) {
return handlerDataSourceConnectError(VipMongo.name, error);
} finally {
await client?.close();
}
}
/**
* 查询表中的数据
* @private
*/
async findTableData(mongoDB, options) {
const filter = options.findFilter == null ? {} : options.findFilter;
const findOptions = {
maxTimeMS: MONGO_DEFAULT_TIMEOUT,
...options.findOptions == null ? {} : options.findOptions
};
const data = await mongoDB.collection(options.table).find(filter, findOptions).toArray();
return { success: true, data };
}
/**
* 建立连接,获取MongoDB客户端
* @private
*/
async getMongoClient(options) {
const url = `mongodb://${options.host}:${options.port}`;
return await mongodb.MongoClient.connect(url, {
auth: { username: options.username, password: options.password }
});
}
}
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function getAugmentedNamespace(n) {
if (n.__esModule) return n;
var f = n.default;
if (typeof f == "function") {
var a = function a () {
if (this instanceof a) {
return Reflect.construct(f, arguments, this.constructor);
}
return f.apply(this, arguments);
};
a.prototype = f.prototype;
} else a = {};
Object.defineProperty(a, '__esModule', {value: true});
Object.keys(n).forEach(function (k) {
var d = Object.getOwnPropertyDescriptor(n, k);
Object.defineProperty(a, k, d.get ? d : {
enumerable: true,
get: function () {
return n[k];
}
});
});
return a;
}
var promise = {};
var SqlString = {};
var hasRequiredSqlString;
function requireSqlString () {
if (hasRequiredSqlString) return SqlString;
hasRequiredSqlString = 1;
(function (exports) {
var SqlString = exports;
var ID_GLOBAL_REGEXP = /`/g;
var QUAL_GLOBAL_REGEXP = /\./g;
var CHARS_GLOBAL_REGEXP = /[\0\b\t\n\r\x1a\"\'\\]/g; // eslint-disable-line no-control-regex
var CHARS_ESCAPE_MAP = {
'\0' : '\\0',
'\b' : '\\b',
'\t' : '\\t',
'\n' : '\\n',
'\r' : '\\r',
'\x1a' : '\\Z',
'"' : '\\"',
'\'' : '\\\'',
'\\' : '\\\\'
};
SqlString.escapeId = function escapeId(val, forbidQualified) {
if (Array.isArray(val)) {
var sql = '';
for (var i = 0; i < val.length; i++) {
sql += (i === 0 ? '' : ', ') + SqlString.escapeId(val[i], forbidQualified);
}
return sql;
} else if (forbidQualified) {
return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``') + '`';
} else {
return '`' + String(val).replace(ID_GLOBAL_REGEXP, '``').replace(QUAL_GLOBAL_REGEXP, '`.`') + '`';
}
};
SqlString.escape = function escape(val, stringifyObjects, timeZone) {
if (val === undefined || val === null) {
return 'NULL';
}
switch (typeof val) {
case 'boolean': return (val) ? 'true' : 'false';
case 'number': return val + '';
case 'object':
if (Object.prototype.toString.call(val) === '[object Date]') {
return SqlString.dateToString(val, timeZone || 'local');
} else if (Array.isArray(val)) {
return SqlString.arrayToList(val, timeZone);
} else if (Buffer.isBuffer(val)) {
return SqlString.bufferToString(val);
} else if (typeof val.toSqlString === 'function') {
return String(val.toSqlString());
} else if (stringifyObjects) {
return escapeString(val.toString());
} else {
return SqlString.objectToValues(val, timeZone);
}
default: return escapeString(val);
}
};
SqlString.arrayToList = function arrayToList(array, timeZone) {
var sql = '';
for (var i = 0; i < array.length; i++) {
var val = array[i];
if (Array.isArray(val)) {
sql += (i === 0 ? '' : ', ') + '(' + SqlString.arrayToList(val, timeZone) + ')';
} else {
sql += (i === 0 ? '' : ', ') + SqlString.escape(val, true, timeZone);
}
}
return sql;
};
SqlString.format = function format(sql, values, stringifyObjects, timeZone) {
if (values == null) {
return sql;
}
if (!Array.isArray(values)) {
values = [values];
}
var chunkIndex = 0;
var placeholdersRegex = /\?+/g;
var result = '';
var valuesIndex = 0;
var match;
while (valuesIndex < values.length && (match = placeholdersRegex.exec(sql))) {
var len = match[0].length;
if (len > 2) {
continue;
}
var value = len === 2
? SqlString.escapeId(values[valuesIndex])
: SqlString.escape(values[valuesIndex], stringifyObjects, timeZone);
result += sql.slice(chunkIndex, match.index) + value;
chunkIndex = placeholdersRegex.lastIndex;
valuesIndex++;
}
if (chunkIndex === 0) {
// Nothing was replaced
return sql;
}
if (chunkIndex < sql.length) {
return result + sql.slice(chunkIndex);
}
return result;
};
SqlString.dateToString = function dateToString(date, timeZone) {
var dt = new Date(date);
if (isNaN(dt.getTime())) {
return 'NULL';
}
var year;
var month;
var day;
var hour;
var minute;
var second;
var millisecond;
if (timeZone === 'local') {
year = dt.getFullYear();
month = dt.getMonth() + 1;
day = dt.getDate();
hour = dt.getHours();
minute = dt.getMinutes();
second = dt.getSeconds();
millisecond = dt.getMilliseconds();
} else {
var tz = convertTimezone(timeZone);
if (tz !== false && tz !== 0) {
dt.setTime(dt.getTime() + (tz * 60000));
}
year = dt.getUTCFullYear();
month = dt.getUTCMonth() + 1;
day = dt.getUTCDate();
hour = dt.getUTCHours();
minute = dt.getUTCMinutes();
second = dt.getUTCSeconds();
millisecond = dt.getUTCMilliseconds();
}
// YYYY-MM-DD HH:mm:ss.mmm
var str = zeroPad(year, 4) + '-' + zeroPad(month, 2) + '-' + zeroPad(day, 2) + ' ' +
zeroPad(hour, 2) + ':' + zeroPad(minute, 2) + ':' + zeroPad(second, 2) + '.' +
zeroPad(millisecond, 3);
return escapeString(str);
};
SqlString.bufferToString = function bufferToString(buffer) {
return 'X' + escapeString(buffer.toString('hex'));
};
SqlString.objectToValues = function objectToValues(object, timeZone) {
var sql = '';
for (var key in object) {
var val = object[key];
if (typeof val === 'function') {
continue;
}
sql += (sql.length === 0 ? '' : ', ') + SqlString.escapeId(key) + ' = ' + SqlString.escape(val, true, timeZone);
}
return sql;
};
SqlString.raw = function raw(sql) {
if (typeof sql !== 'string') {
throw new TypeError('argument sql must be a string');
}
return {
toSqlString: function toSqlString() { return sql; }
};
};
function escapeString(val) {
var chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex = 0;
var escapedVal = '';
var match;
while ((match = CHARS_GLOBAL_REGEXP.exec(val))) {
escapedVal += val.slice(chunkIndex, match.index) + CHARS_ESCAPE_MAP[match[0]];
chunkIndex = CHARS_GLOBAL_REGEXP.lastIndex;
}
if (chunkIndex === 0) {
// Nothing was escaped
return "'" + val + "'";
}
if (chunkIndex < val.length) {
return "'" + escapedVal + val.slice(chunkIndex) + "'";
}
return "'" + escapedVal + "'";
}
function zeroPad(number, length) {
number = number.toString();
while (number.length < length) {
number = '0' + number;
}
return number;
}
function convertTimezone(tz) {
if (tz === 'Z') {
return 0;
}
var m = tz.match(/([\+\-\s])(\d\d):?(\d\d)?/);
if (m) {
return (m[1] === '-' ? -1 : 1) * (parseInt(m[2], 10) + ((m[3] ? parseInt(m[3], 10) : 0) / 60)) * 60;
}
return false;
}
} (SqlString));
return SqlString;
}
var sqlstring;
var hasRequiredSqlstring;
function requireSqlstring () {
if (hasRequiredSqlstring) return sqlstring;
hasRequiredSqlstring = 1;
sqlstring = requireSqlString();
return sqlstring;
}
var lib$2 = {};
var hasRequiredLib$1;
function requireLib$1 () {
if (hasRequiredLib$1) return lib$2;
hasRequiredLib$1 = 1;
Object.defineProperty(lib$2, "__esModule", { value: true });
lib$2.createLRU = void 0;
const createLRU = (options) => {
let { max, onEviction } = options;
if (!(Number.isInteger(max) && max > 0))
throw new TypeError('`max` must be a positive integer');
let size = 0;
let head = 0;
let tail = 0;
let free = [];
const keyMap = new Map();
const keyList = new Array(max).fill(undefined);
const valList = new Array(max).fill(undefined);
const next = new Array(max).fill(0);
const prev = new Array(max).fill(0);
const setTail = (index, type) => {
if (index === tail)
return;
const nextIndex = next[index];
const prevIndex = prev[index];
if (index === head)
head = nextIndex;
else if (type === 'get' || prevIndex !== 0)
next[prevIndex] = nextIndex;
if (nextIndex !== 0)
prev[nextIndex] = prevIndex;
next[tail] = index;
prev[index] = tail;
next[index] = 0;
tail = index;
};
const _evict = () => {
const evictHead = head;
const key = keyList[evictHead];
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[evictHead]);
keyMap.delete(key);
keyList[evictHead] = undefined;
valList[evictHead] = undefined;
head = next[evictHead];
if (head !== 0)
prev[head] = 0;
size--;
if (size === 0)
head = tail = 0;
free.push(evictHead);
return evictHead;
};
return {
/** Adds a key-value pair to the cache. Updates the value if the key already exists. */
set(key, value) {
if (key === undefined)
return;
let index = keyMap.get(key);
if (index === undefined) {
index = size === max ? _evict() : free.length > 0 ? free.pop() : size;
keyMap.set(key, index);
keyList[index] = key;
size++;
}
else
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[index]);
valList[index] = value;
if (size === 1)
head = tail = index;
else
setTail(index, 'set');
},
/** Retrieves the value for a given key and moves the key to the most recent position. */
get(key) {
const index = keyMap.get(key);
if (index === undefined)
return;
if (index !== tail)
setTail(index, 'get');
return valList[index];
},
/** Retrieves the value for a given key without changing its position. */
peek: (key) => {
const index = keyMap.get(key);
return index !== undefined ? valList[index] : undefined;
},
/** Checks if a key exists in the cache. */
has: (key) => keyMap.has(key),
/** Iterates over all keys in the cache, from most recent to least recent. */
*keys() {
let current = tail;
for (let i = 0; i < size; i++) {
yield keyList[current];
current = prev[current];
}
},
/** Iterates over all values in the cache, from most recent to least recent. */
*values() {
let current = tail;
for (let i = 0; i < size; i++) {
yield valList[current];
current = prev[current];
}
},
/** Iterates over `[key, value]` pairs in the cache, from most recent to least recent. */
*entries() {
let current = tail;
for (let i = 0; i < size; i++) {
yield [keyList[current], valList[current]];
current = prev[current];
}
},
/** Iterates over each value-key pair in the cache, from most recent to least recent. */
forEach: (callback) => {
let current = tail;
for (let i = 0; i < size; i++) {
const key = keyList[current];
const value = valList[current];
callback(value, key);
current = prev[current];
}
},
/** Deletes a key-value pair from the cache. */
delete(key) {
const index = keyMap.get(key);
if (index === undefined)
return false;
onEviction === null || onEviction === void 0 ? void 0 : onEviction(key, valList[index]);
keyMap.delete(key);
free.push(index);
keyList[index] = undefined;
valList[index] = undefined;
const prevIndex = prev[index];
const nextIndex = next[index];
if (prevIndex !== 0)
next[prevIndex] = nextIndex;
if (nextIndex !== 0)
prev[nextIndex] = prevIndex;
if (index === head)
head = nextIndex;
if (index === tail)
tail = prevIndex;
size--;
return true;
},
/** Evicts the oldest item or the specified number of the oldest items from the cache. */
evict: (number) => {
let toPrune = Math.min(number, size);
while (toPrune > 0) {
_evict();
toPrune--;
}
},
/** Clears all key-value pairs from the cache. */
clear() {
if (typeof onEviction === 'function') {
const iterator = keyMap.values();
for (let result = iterator.next(); !result.done; result = iterator.next())
onEviction(keyList[result.value], valList[result.value]);
}
keyMap.clear();
keyList.fill(undefined);
valList.fill(undefined);
free = [];
size = 0;
head = tail = 0;
},
/** Resizes the cache to a new maximum size, evicting items if necessary. */
resize: (newMax) => {
if (!(Number.isInteger(newMax) && newMax > 0))
throw new TypeError('`max` must be a positive integer');
if (newMax === max)
return;
if (newMax < max) {
let current = tail;
const preserve = Math.min(size, newMax);
const remove = size - preserve;
const newKeyList = new Array(newMax);
const newValList = new Array(newMax);
const newNext = new Array(newMax);
const newPrev = new Array(newMax);
for (let i = 1; i <= remove; i++)
onEviction === null || onEviction === void 0 ? void 0 : onEviction(keyList[i], valList[i]);
for (let i = preserve - 1; i >= 0; i--) {
newKeyList[i] = keyList[current];
newValList[i] = valList[current];
newNext[i] = i + 1;
newPrev[i] = i - 1;
keyMap.set(newKeyList[i], i);
current = prev[current];
}
head = 0;
tail = preserve - 1;
size = preserve;
keyList.length = newMax;
valList.length = newMax;
next.length = newMax;
prev.length = newMax;
for (let i = 0; i < preserve; i++) {
keyList[i] = newKeyList[i];
valList[i] = newValList[i];
next[i] = newNext[i];
prev[i] = newPrev[i];
}
free = [];
for (let i = preserve; i < newMax; i++)
free.push(i);
}
else {
const fill = newMax - max;
keyList.push(...new Array(fill).fill(undefined));
valList.push(...new Array(fill).fill(undefined));
next.push(...new Array(fill).fill(0));
prev.push(...new Array(fill).fill(0));
}
max = newMax;
},
/** Returns the maximum number of items that can be stored in the cache. */
get max() {
return max;
},
/** Returns the number of items currently stored in the cache. */
get size() {
return size;
},
/** Returns the number of currently available slots in the cache before reaching the maximum size. */
get available() {
return max - size;
},
};
};
lib$2.createLRU = createLRU;
return lib$2;
}
var parser_cache;
var hasRequiredParser_cache;
function requireParser_cache () {
if (hasRequiredParser_cache) return parser_cache;
hasRequiredParser_cache = 1;
const { createLRU } = requireLib$1();
const parserCache = createLRU({
max: 15000,
});
function keyFromFields(type, fields, options, config) {
const res = [
type,
typeof options.nestTables,
options.nestTables,
Boolean(options.rowsAsArray),
Boolean(options.supportBigNumbers || config.supportBigNumbers),
Boolean(options.bigNumberStrings || config.bigNumberStrings),
typeof options.typeCast,
options.timezone || config.timezone,
Boolean(options.decimalNumbers),
options.dateStrings,
];
for (let i = 0; i < fields.length; ++i) {
const field = fields[i];
res.push([
field.name,
field.columnType,
field.length,
field.schema,
field.table,
field.flags,
field.characterSet,
]);
}
return JSON.stringify(res, null, 0);
}
function getParser(type, fields, options, config, compiler) {
const key = keyFromFields(type, fields, options, config);
let parser = parserCache.get(key);
if (parser) {
return parser;
}
parser = compiler(fields, options, config);
parserCache.set(key, parser);
return parser;
}
function setMaxCache(max) {
parserCache.resize(max);
}
function clearCache() {
parserCache.clear();
}
parser_cache = {
getParser: getParser,
setMaxCache: setMaxCache,
clearCache: clearCache,
_keyFromFields: keyFromFields,
};
return parser_cache;
}
var denque;
var hasRequiredDenque;
function requireDenque () {
if (hasRequiredDenque) return denque;
hasRequiredDenque = 1;
/**
* Custom implementation of a double ended queue.
*/
function Denque(array, options) {
var options = options || {};
this._capacity = options.capacity;
this._head = 0;
this._tail = 0;
if (Array.isArray(array)) {
this._fromArray(array);
} else {
this._capacityMask = 0x3;
this._list = new Array(4);
}
}
/**
* --------------
* PUBLIC API
* -------------
*/
/**
* Returns the item at the specified index from the list.
* 0 is the first element, 1 is the second, and so on...
* Elements at negative values are that many from the end: -1 is one before the end
* (the last element), -2 is two before the end (one before last), etc.
* @param index
* @returns {*}
*/
Denque.prototype.peekAt = function peekAt(index) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
var len = this.size();
if (i >= len || i < -len) return undefined;
if (i < 0) i += len;
i = (this._head + i) & this._capacityMask;
return this._list[i];
};
/**
* Alias for peekAt()
* @param i
* @returns {*}
*/
Denque.prototype.get = function get(i) {
return this.peekAt(i);
};
/**
* Returns the first item in the list without removing it.
* @returns {*}
*/
Denque.prototype.peek = function peek() {
if (this._head === this._tail) return undefined;
return this._list[this._head];
};
/**
* Alias for peek()
* @returns {*}
*/
Denque.prototype.peekFront = function peekFront() {
return this.peek();
};
/**
* Returns the item that is at the back of the queue without removing it.
* Uses peekAt(-1)
*/
Denque.prototype.peekBack = function peekBack() {
return this.peekAt(-1);
};
/**
* Returns the current length of the queue
* @return {Number}
*/
Object.defineProperty(Denque.prototype, 'length', {
get: function length() {
return this.size();
}
});
/**
* Return the number of items on the list, or 0 if empty.
* @returns {number}
*/
Denque.prototype.size = function size() {
if (this._head === this._tail) return 0;
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Add an item at the beginning of the list.
* @param item
*/
Denque.prototype.unshift = function unshift(item) {
if (arguments.length === 0) return this.size();
var len = this._list.length;
this._head = (this._head - 1 + len) & this._capacityMask;
this._list[this._head] = item;
if (this._tail === this._head) this._growArray();
if (this._capacity && this.size() > this._capacity) this.pop();
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Remove and return the first item on the list,
* Returns undefined if the list is empty.
* @returns {*}
*/
Denque.prototype.shift = function shift() {
var head = this._head;
if (head === this._tail) return undefined;
var item = this._list[head];
this._list[head] = undefined;
this._head = (head + 1) & this._capacityMask;
if (head < 2 && this._tail > 10000 && this._tail <= this._list.length >>> 2) this._shrinkArray();
return item;
};
/**
* Add an item to the bottom of the list.
* @param item
*/
Denque.prototype.push = function push(item) {
if (arguments.length === 0) return this.size();
var tail = this._tail;
this._list[tail] = item;
this._tail = (tail + 1) & this._capacityMask;
if (this._tail === this._head) {
this._growArray();
}
if (this._capacity && this.size() > this._capacity) {
this.shift();
}
if (this._head < this._tail) return this._tail - this._head;
else return this._capacityMask + 1 - (this._head - this._tail);
};
/**
* Remove and return the last item on the list.
* Returns undefined if the list is empty.
* @returns {*}
*/
Denque.prototype.pop = function pop() {
var tail = this._tail;
if (tail === this._head) return undefined;
var len = this._list.length;
this._tail = (tail - 1 + len) & this._capacityMask;
var item = this._list[this._tail];
this._list[this._tail] = undefined;
if (this._head < 2 && tail > 10000 && tail <= len >>> 2) this._shrinkArray();
return item;
};
/**
* Remove and return the item at the specified index from the list.
* Returns undefined if the list is empty.
* @param index
* @returns {*}
*/
Denque.prototype.removeOne = function removeOne(index) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
if (this._head === this._tail) return void 0;
var size = this.size();
var len = this._list.length;
if (i >= size || i < -size) return void 0;
if (i < 0) i += size;
i = (this._head + i) & this._capacityMask;
var item = this._list[i];
var k;
if (index < size / 2) {
for (k = index; k > 0; k--) {
this._list[i] = this._list[i = (i - 1 + len) & this._capacityMask];
}
this._list[i] = void 0;
this._head = (this._head + 1 + len) & this._capacityMask;
} else {
for (k = size - 1 - index; k > 0; k--) {
this._list[i] = this._list[i = (i + 1 + len) & this._capacityMask];
}
this._list[i] = void 0;
this._tail = (this._tail - 1 + len) & this._capacityMask;
}
return item;
};
/**
* Remove number of items from the specified index from the list.
* Returns array of removed items.
* Returns undefined if the list is empty.
* @param index
* @param count
* @returns {array}
*/
Denque.prototype.remove = function remove(index, count) {
var i = index;
var removed;
var del_count = count;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
if (this._head === this._tail) return void 0;
var size = this.size();
var len = this._list.length;
if (i >= size || i < -size || count < 1) return void 0;
if (i < 0) i += size;
if (count === 1 || !count) {
removed = new Array(1);
removed[0] = this.removeOne(i);
return removed;
}
if (i === 0 && i + count >= size) {
removed = this.toArray();
this.clear();
return removed;
}
if (i + count > size) count = size - i;
var k;
removed = new Array(count);
for (k = 0; k < count; k++) {
removed[k] = this._list[(this._head + i + k) & this._capacityMask];
}
i = (this._head + i) & this._capacityMask;
if (index + count === size) {
this._tail = (this._tail - count + len) & this._capacityMask;
for (k = count; k > 0; k--) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
}
return removed;
}
if (index === 0) {
this._head = (this._head + count + len) & this._capacityMask;
for (k = count - 1; k > 0; k--) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
}
return removed;
}
if (i < size / 2) {
this._head = (this._head + index + count + len) & this._capacityMask;
for (k = index; k > 0; k--) {
this.unshift(this._list[i = (i - 1 + len) & this._capacityMask]);
}
i = (this._head - 1 + len) & this._capacityMask;
while (del_count > 0) {
this._list[i = (i - 1 + len) & this._capacityMask] = void 0;
del_count--;
}
if (index < 0) this._tail = i;
} else {
this._tail = i;
i = (i + count + len) & this._capacityMask;
for (k = size - (count + index); k > 0; k--) {
this.push(this._list[i++]);
}
i = this._tail;
while (del_count > 0) {
this._list[i = (i + 1 + len) & this._capacityMask] = void 0;
del_count--;
}
}
if (this._head < 2 && this._tail > 10000 && this._tail <= len >>> 2) this._shrinkArray();
return removed;
};
/**
* Native splice implementation.
* Remove number of items from the specified index from the list and/or add new elements.
* Returns array of removed items or empty array if count == 0.
* Returns undefined if the list is empty.
*
* @param index
* @param count
* @param {...*} [elements]
* @returns {array}
*/
Denque.prototype.splice = function splice(index, count) {
var i = index;
// expect a number or return undefined
if ((i !== (i | 0))) {
return void 0;
}
var size = this.size();
if (i < 0) i += size;
if (i > size) return void 0;
if (arguments.length > 2) {
var k;
var temp;
var removed;
var arg_len = arguments.length;
var len = this._list.length;
var arguments_index = 2;
if (!size || i < size / 2) {
temp = new Array(i);
for (k = 0; k < i; k++) {
temp[k] = this._list[(this._head + k) & this._capacityMask];
}
if (count === 0) {
removed = [];
if (i > 0) {
this._head = (this._head + i + len) & this._capacityMask;
}
} else {
removed = this.remove(i, count);
this._head = (this._head + i + len) & this._capacityMask;
}
while (arg_len > arguments_index) {
this.unshift(arguments[--arg_len]);
}
for (k = i; k > 0; k--) {
this.unshift(temp[k - 1]);
}
} else {
temp = new Array(size - (i + count));
var leng = temp.length;
for (k = 0; k < leng; k++) {
temp[k] = this._list[(this._head + i + count + k) & this._capacityMask];
}
if (count === 0) {
removed = [];
if (i != size) {
this._tail = (this._head + i + len) & this._capacityMask;
}
} else {
removed = this.remove(i, count);
this._tail = (this._tail - leng + len) & this._capacityMask;
}
while (arguments_index < arg_len) {
this.push(arguments[arguments_index++]);
}
for (k = 0; k < leng; k++) {
this.push(temp[k]);
}
}
return removed;
} else {
return this.remove(i, count);
}
};
/**
* Soft clear - does not reset capacity.
*/
Denque.prototype.clear = function clear() {
this._list = new Array(this._list.length);
this._head = 0;
this._tail = 0;
};
/**
* Returns true or false whether the list is empty.
* @returns {boolean}
*/
Denque.prototype.isEmpty = function isEmpty() {
return this._head === this._tail;
};
/**
* Returns an array of all queue items.
* @returns {Array}
*/
Denque.prototype.toArray = function toArray() {
return this._copyArray(false);
};
/**
* -------------
* INTERNALS
* -------------
*/
/**
* Fills the queue with items from an array
* For use in the constructor
* @param array
* @private
*/
Denque.prototype._fromArray = function _fromArray(array) {
var length = array.length;
var capacity = this._nextPowerOf2(length);
this._list = new Array(capacity);
this._capacityMask = capacity - 1;
this._tail = length;
for (var i = 0; i < length; i++) this._list[i] = array[i];
};
/**
*
* @param fullCopy
* @param size Initialize the array with a specific size. Will default to the current list size
* @returns {Array}
* @private
*/
Denque.prototype._copyArray = function _copyArray(fullCopy, size) {
var src = this._list;
var capacity = src.length;
var length = this.length;
size = size | length;
// No prealloc requested and the buffer is contiguous
if (size == length && this._head < this._tail) {
// Simply do a fast slice copy
return this._list.slice(this._head, this._tail);
}
var dest = new Array(size);
var k = 0;
var i;
if (fullCopy || this._head > this._tail) {
for (i = this._head; i < capacity; i++) dest[k++] = src[i];
for (i = 0; i < this._tail; i++) dest[k++] = src[i];
} else {
for (i = this._head; i < this._tail; i++) dest[k++] = src[i];
}
return dest;
};
/**
* Grows the internal list array.
* @private
*/
Denque.prototype._growArray = function _growArray() {
if (this._head != 0) {
// double array size and copy existing data, head to end, then beginning to tail.
var newList = this._copyArray(true, this._list.length << 1);
this._tail = this._list.length;
this._head = 0;
this._list = newList;
} else {
this._tail = this._list.length;
this._list.length <<= 1;
}
this._capacityMask = (this._capacityMask << 1) | 1;
};
/**
* Shrinks the internal list array.
* @private
*/
Denque.prototype._shrinkArray = function _shrinkArray() {
this._list.length >>>= 1;
this._capacityMask >>>= 1;
};
/**
* Find the next power of 2, at least 4
* @private
* @param {number} num
* @returns {number}
*/
Denque.prototype._nextPowerOf2 = function _nextPowerOf2(num) {
var log2 = Math.log(num) / Math.log(2);
var nextPow2 = 1 << (log2 + 1);
return Math.max(nextPow2, 4);
};
denque = Denque;
return denque;
}
var errors = {};
var hasRequiredErrors;
function requireErrors () {
if (hasRequiredErrors) return errors;
hasRequiredErrors = 1;
(function (exports) {
// originally copied from https://raw.githubusercontent.com/mysqljs/mysql/7770ee5bb13260c56a160b91fe480d9165dbeeba/lib/protocol/constants/errors.js
// (c) node-mysql authors
// updated to contain error codes as is contained in MySQL 8.0
// by adapting node-mysql: /.../generate-error-constants.js
/**
* MySQL error constants
*
* Extracted from version 8.0.33
*
* !! Generated by generate-error-constants.js, do not modify by hand !!
*/
exports.EE_CANTCREATEFILE = 1;
exports.EE_READ = 2;
exports.EE_WRITE = 3;
exports.EE_BADCLOSE = 4;
exports.EE_OUTOFMEMORY = 5;
exports.EE_DELETE = 6;
exports.EE_LINK = 7;
exports.EE_EOFERR = 9;
exports.EE_CANTLOCK = 10;
exports.EE_CANTUNLOCK = 11;
exports.EE_DIR = 12;
exports.EE_STAT = 13;
exports.EE_CANT_CHSIZE = 14;
exports.EE_CANT_OPEN_STREAM = 15;
exports.EE_GETWD = 16;
exports.EE_SETWD = 17;
exports.EE_LINK_WARNING = 18;
exports.EE_OPEN_WARNING = 19;
exports.EE_DISK_FULL = 20;
exports.EE_CANT_MKDIR = 21;
exports.EE_UNKNOWN_CHARSET = 22;
exports.EE_OUT_OF_FILERESOURCES = 23;
exports.EE_CANT_READLINK = 24;
exports.EE_CANT_SYMLINK = 25;
exports.EE_REALPATH = 26;
exports.EE_SYNC = 27;
exports.EE_UNKNOWN_COLLATION = 28;
exports.EE_FILENOTFOUND = 29;
exports.EE_FILE_NOT_CLOSED = 30;
exports.EE_CHANGE_OWNERSHIP = 31;
exports.EE_CHANGE_PERMISSIONS = 32;
exports.EE_CANT_SEEK = 33;
exports.EE_CAPACITY_EXCEEDED = 34;
exports.EE_DISK_FULL_WITH_RETRY_MSG = 35;
exports.EE_FAILED_TO_CREATE_TIMER = 36;
exports.EE_FAILED_TO_DELETE_TIMER = 37;
exports.EE_FAILED_TO_CREATE_TIMER_QUEUE = 38;
exports.EE_FAILED_TO_START_TIMER_NOTIFY_THREAD = 39;
exports.EE_FAILED_TO_CREATE_TIMER_NOTIFY_THREAD_INTERRUPT_EVENT = 40;
exports.EE_EXITING_TIMER_NOTIFY_THREAD = 41;
exports.EE_WIN_LIBRARY_LOAD_FAILED = 42;
exports.EE_WIN_RUN_TIME_ERROR_CHECK = 43;
exports.EE_FAILED_TO_DETERMINE_LARGE_PAGE_SIZE = 44;
exports.EE_FAILED_TO_KILL_ALL_THREADS = 45;
exports.EE_FAILED_TO_CREATE_IO_COMPLETION_PORT = 46;
exports.EE_FAILED_TO_OPEN_DEFAULTS_FILE = 47;
exports.EE_FAILED_TO_HANDLE_DEFAULTS_FILE = 48;
exports.EE_WRONG_DIRECTIVE_IN_CONFIG_FILE = 49;
exports.EE_SKIPPING_DIRECTIVE_DUE_TO_MAX_INCLUDE_RECURSION = 50;
exports.EE_INCORRECT_GRP_DEFINITION_IN_CONFIG_FILE = 51;
exports.EE_OPTION_WITHOUT_GRP_IN_CONFIG_FILE = 52;
exports.EE_CONFIG_FILE_PERMISSION_ERROR = 53;
exports.EE_IGNORE_WORLD_WRITABLE_CONFIG_FILE = 54;
exports.EE_USING_DISABLED_OPTION = 55;
exports.EE_USING_DISABLED_SHORT_OPTION = 56;
exports.EE_USING_PASSWORD_ON_CLI_IS_INSECURE = 57;
exports.EE_UNKNOWN_SUFFIX_FOR_VARIABLE = 58;
exports.EE_SSL_ERROR_FROM_FILE = 59;
exports.EE_SSL_ERROR = 60;
exports.EE_NET_SEND_ERROR_IN_BOOTSTRAP = 61;
exports.EE_PACKETS_OUT_OF_ORDER = 62;
exports.EE_UNKNOWN_PROTOCOL_OPTION = 63;
exports.EE_FAILED_TO_LOCATE_SERVER_PUBLIC_KEY = 64;
exports.EE_PUBLIC_KEY_NOT_IN_PEM_FORMAT = 65;
exports.EE_DEBUG_INFO = 66;
exports.EE_UNKNOWN_VARIABLE = 67;
exports.EE_UNKNOWN_OPTION = 68;
exports.EE_UNKNOWN_SHORT_OPTION = 69;
exports.EE_OPTION_WITHOUT_ARGUMENT = 70;
exports.EE_OPTION_REQUIRES_ARGUMENT = 71;
exports.EE_SHORT_OPTION_REQUIRES_ARGUMENT = 72;
exports.EE_OPTION_IGNORED_DUE_TO_INVALID_VALUE = 73;
exports.EE_OPTION_WITH_EMPTY_VALUE = 74;
exports.EE_FAILED_TO_ASSIGN_MAX_VALUE_TO_OPTION = 75;
exports.EE_INCORRECT_BOOLEAN_VALUE_FOR_OPTION = 76;
exports.EE_FAILED_TO_SET_OPTION_VALUE = 77;
exports.EE_INCORRECT_INT_VALUE_FOR_OPTION = 78;
exports.EE_INCORRECT_UINT_VALUE_FOR_OPTION = 79;
exports.EE_ADJUSTED_SIGNED_VALUE_FOR_OPTION = 80;
exports.EE_ADJUSTED_UNSIGNED_VALUE_FOR_OPTION = 81;
exports.EE_ADJUSTED_ULONGLONG_VALUE_FOR_OPTION = 82;
exports.EE_ADJUSTED_DOUBLE_VALUE_FOR_OPTION = 83;
exports.EE_INVALID_DECIMAL_VALUE_FOR_OPTION = 84;
exports.EE_COLLATION_PARSER_ERROR = 85;
exports.EE_FAILED_TO_RESET_BEFORE_PRIMARY_IGNORABLE_CHAR = 86;
exports.EE_FAILED_TO_RESET_BEFORE_TERTIARY_IGNORABLE_CHAR = 87;
exports.EE_SHIFT_CHAR_OUT_OF_RANGE = 88;
exports.EE_RESET_CHAR_OUT_OF_RANGE = 89;
exports.EE_UNKNOWN_LDML_TAG = 90;
exports.EE_FAILED_TO_RESET_BEFORE_SECONDARY_IGNORABLE_CHAR = 91;
exports.EE_FAILED_PROCESSING_DIRECTIVE = 92;
exports.EE_PTHREAD_KILL_FAILED = 93;
exports.HA_ERR_KEY_NOT_FOUND = 120;
exports.HA_ERR_FOUND_DUPP_KEY = 121;
exports.HA_ERR_INTERNAL_ERROR = 122;
exports.HA_ERR_RECORD_CHANGED = 123;
exports.HA_ERR_WRONG_INDEX = 124;
exports.HA_ERR_ROLLED_BACK = 125;
exports.HA_ERR_CRASHED = 126;
exports.HA_ERR_WRONG_IN_RECORD = 127;
exports.HA_ERR_OUT_OF_MEM = 128;
exports.HA_ERR_NOT_A_TABLE = 130;
exports.HA_ERR_WRONG_COMMAND = 131;
exports.HA_ERR_OLD_FILE = 132;
exports.HA_ERR_NO_ACTIVE_RECORD = 133;
exports.HA_ERR_RECORD_DELETED = 134;
exports.HA_ERR_RECORD_FILE_FULL = 135;
exports.HA_ERR_INDEX_FILE_FULL = 136;
exports.HA_ERR_END_OF_FILE = 137;
exports.HA_ERR_UNSUPPORTED = 138;
exports.HA_ERR_TOO_BIG_ROW = 139;
exports.HA_WRONG_CREATE_OPTION = 140;
exports.HA_ERR_FOUND_DUPP_UNIQUE = 141;
exports.HA_ERR_UNKNOWN_CHARSET = 142;
exports.HA_ERR_WRONG_MRG_TABLE_DEF = 143;
exports.HA_ERR_CRASHED_ON_REPAIR = 144;
exports.HA_ERR_CRASHED_ON_USAGE = 145;
exports.HA_ERR_LOCK_WAIT_TIMEOUT = 146;
exports.HA_ERR_LOCK_TABLE_FULL = 147;
exports.HA_ERR_READ_ONLY_TRANSACTION = 148;
exports.HA_ERR_LOCK_DEADLOCK = 149;
exports.HA_ERR_CANNOT_ADD_FOREIGN = 150;
exports.HA_ERR_NO_REFERENCED_ROW = 151;
exports.HA_ERR_ROW_IS_REFERENCED = 152;
exports.HA_ERR_NO_SAVEPOINT = 153;
exports.HA_ERR_NON_UNIQUE_BLOCK_SIZE = 154;
exports.HA_ERR_NO_SUCH_TABLE = 155;
exports.HA_ERR_TABLE_EXIST = 156;
exports.HA_ERR_NO_CONNECTION = 157;
exports.HA_ERR_NULL_IN_SPATIAL = 158;
exports.HA_ERR_TABLE_DEF_CHANGED = 159;
exports.HA_ERR_NO_PARTITION_FOUND = 160;
exports.HA_ERR_RBR_LOGGING_FAILED = 161;
exports.HA_ERR_DROP_INDEX_FK = 162;
exports.HA_ERR_FOREIGN_DUPLICATE_KEY = 163;
exports.HA_ERR_TABLE_NEEDS_UPGRADE = 164;
exports.HA_ERR_TABLE_READONLY