123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- 'use strict';
- const ResultSet = require('./resultset');
- const FieldDetail = require('../const/field-detail');
- const FieldType = require('../const/field-type');
- const Long = require('long');
- const moment = require('moment-timezone');
- const QUOTE = 0x27;
- class CommonText extends ResultSet {
- constructor(resolve, reject, cmdOpts, connOpts, sql, values) {
- super(resolve, reject);
- this.configAssign(connOpts, cmdOpts);
- this.sql = sql;
- this.initialValues = values;
- this.getDateQuote = this.opts.tz
- ? this.opts.tz === 'Etc/UTC'
- ? CommonText.getUtcDate
- : CommonText.getTimezoneDate
- : CommonText.getLocalDate;
- }
- /**
- * Write (and escape) current parameter value to output writer
- *
- * @param out output writer
- * @param value current parameter
- * @param opts connection options
- * @param info connection information
- */
- writeParam(out, value, opts, info) {
- switch (typeof value) {
- case 'boolean':
- out.writeStringAscii(value ? 'true' : 'false');
- break;
- case 'bigint':
- case 'number':
- out.writeStringAscii('' + value);
- break;
- case 'object':
- if (value === null) {
- out.writeStringAscii('NULL');
- } else if (Object.prototype.toString.call(value) === '[object Date]') {
- out.writeStringAscii(this.getDateQuote(value, opts));
- } else if (Buffer.isBuffer(value)) {
- out.writeStringAscii("_BINARY '");
- out.writeBufferEscape(value);
- out.writeInt8(QUOTE);
- } else if (typeof value.toSqlString === 'function') {
- out.writeStringEscapeQuote(String(value.toSqlString()));
- } else if (Long.isLong(value)) {
- out.writeStringAscii(value.toString());
- } else if (Array.isArray(value)) {
- if (opts.arrayParenthesis) {
- out.writeStringAscii('(');
- }
- for (let i = 0; i < value.length; i++) {
- if (i !== 0) out.writeStringAscii(',');
- this.writeParam(out, value[i], opts, info);
- }
- if (opts.arrayParenthesis) {
- out.writeStringAscii(')');
- }
- } else {
- if (
- value.type != null &&
- [
- 'Point',
- 'LineString',
- 'Polygon',
- 'MultiPoint',
- 'MultiLineString',
- 'MultiPolygon',
- 'GeometryCollection'
- ].includes(value.type)
- ) {
- //GeoJSON format.
- let prefix =
- (info.isMariaDB() && info.hasMinVersion(10, 1, 4)) ||
- (!info.isMariaDB() && info.hasMinVersion(5, 7, 6))
- ? 'ST_'
- : '';
- switch (value.type) {
- case 'Point':
- out.writeStringAscii(
- prefix +
- "PointFromText('POINT(" +
- CommonText.geoPointToString(value.coordinates) +
- ")')"
- );
- break;
- case 'LineString':
- out.writeStringAscii(
- prefix +
- "LineFromText('LINESTRING(" +
- CommonText.geoArrayPointToString(value.coordinates) +
- ")')"
- );
- break;
- case 'Polygon':
- out.writeStringAscii(
- prefix +
- "PolygonFromText('POLYGON(" +
- CommonText.geoMultiArrayPointToString(value.coordinates) +
- ")')"
- );
- break;
- case 'MultiPoint':
- out.writeStringAscii(
- prefix +
- "MULTIPOINTFROMTEXT('MULTIPOINT(" +
- CommonText.geoArrayPointToString(value.coordinates) +
- ")')"
- );
- break;
- case 'MultiLineString':
- out.writeStringAscii(
- prefix +
- "MLineFromText('MULTILINESTRING(" +
- CommonText.geoMultiArrayPointToString(value.coordinates) +
- ")')"
- );
- break;
- case 'MultiPolygon':
- out.writeStringAscii(
- prefix +
- "MPolyFromText('MULTIPOLYGON(" +
- CommonText.geoMultiPolygonToString(value.coordinates) +
- ")')"
- );
- break;
- case 'GeometryCollection':
- out.writeStringAscii(
- prefix +
- "GeomCollFromText('GEOMETRYCOLLECTION(" +
- CommonText.geometricCollectionToString(value.geometries) +
- ")')"
- );
- break;
- }
- } else {
- if (opts.permitSetMultiParamEntries) {
- let first = true;
- for (let key in value) {
- const val = value[key];
- if (typeof val === 'function') continue;
- if (first) {
- first = false;
- } else {
- out.writeStringAscii(',');
- }
- out.writeString('`' + key + '`');
- out.writeStringAscii('=');
- this.writeParam(out, val, opts, info);
- }
- if (first) out.writeStringEscapeQuote(JSON.stringify(value));
- } else {
- out.writeStringEscapeQuote(JSON.stringify(value));
- }
- }
- }
- break;
- default:
- out.writeStringEscapeQuote(value);
- }
- }
- static geometricCollectionToString(geo) {
- if (!geo) return '';
- let st = '';
- for (let i = 0; i < geo.length; i++) {
- //GeoJSON format.
- st += i !== 0 ? ',' : '';
- switch (geo[i].type) {
- case 'Point':
- st += 'POINT(' + CommonText.geoPointToString(geo[i].coordinates) + ')';
- break;
- case 'LineString':
- st += 'LINESTRING(' + CommonText.geoArrayPointToString(geo[i].coordinates) + ')';
- break;
- case 'Polygon':
- st += 'POLYGON(' + CommonText.geoMultiArrayPointToString(geo[i].coordinates) + ')';
- break;
- case 'MultiPoint':
- st += 'MULTIPOINT(' + CommonText.geoArrayPointToString(geo[i].coordinates) + ')';
- break;
- case 'MultiLineString':
- st +=
- 'MULTILINESTRING(' + CommonText.geoMultiArrayPointToString(geo[i].coordinates) + ')';
- break;
- case 'MultiPolygon':
- st += 'MULTIPOLYGON(' + CommonText.geoMultiPolygonToString(geo[i].coordinates) + ')';
- break;
- }
- }
- return st;
- }
- static geoMultiPolygonToString(coords) {
- if (!coords) return '';
- let st = '';
- for (let i = 0; i < coords.length; i++) {
- st += (i !== 0 ? ',(' : '(') + CommonText.geoMultiArrayPointToString(coords[i]) + ')';
- }
- return st;
- }
- static geoMultiArrayPointToString(coords) {
- if (!coords) return '';
- let st = '';
- for (let i = 0; i < coords.length; i++) {
- st += (i !== 0 ? ',(' : '(') + CommonText.geoArrayPointToString(coords[i]) + ')';
- }
- return st;
- }
- static geoArrayPointToString(coords) {
- if (!coords) return '';
- let st = '';
- for (let i = 0; i < coords.length; i++) {
- st += (i !== 0 ? ',' : '') + CommonText.geoPointToString(coords[i]);
- }
- return st;
- }
- static geoPointToString(coords) {
- if (!coords) return '';
- return (isNaN(coords[0]) ? '' : coords[0]) + ' ' + (isNaN(coords[1]) ? '' : coords[1]);
- }
- parseRowAsArray(columns, packet, connOpts) {
- const row = new Array(this._columnCount);
- for (let i = 0; i < this._columnCount; i++) {
- row[i] = this._getValue(i, columns[i], this.opts, connOpts, packet);
- }
- return row;
- }
- parseRowNested(columns, packet, connOpts) {
- const row = {};
- for (let i = 0; i < this._columnCount; i++) {
- if (!row[this.tableHeader[i][0]]) row[this.tableHeader[i][0]] = {};
- row[this.tableHeader[i][0]][this.tableHeader[i][1]] = this._getValue(
- i,
- columns[i],
- this.opts,
- connOpts,
- packet
- );
- }
- return row;
- }
- parseRowStd(columns, packet, connOpts) {
- const row = {};
- for (let i = 0; i < this._columnCount; i++) {
- row[this.tableHeader[i]] = this._getValue(i, columns[i], this.opts, connOpts, packet);
- }
- return row;
- }
- castTextWrapper(column, opts, connOpts, packet) {
- column.string = () => packet.readStringLength();
- column.buffer = () => packet.readBufferLengthEncoded();
- column.float = () => packet.readFloatLengthCoded();
- column.int = () => packet.readIntLengthEncoded();
- column.long = () =>
- packet.readLongLengthEncoded(
- opts.supportBigInt,
- opts.supportBigNumbers,
- opts.bigNumberStrings,
- (column.flags & FieldDetail.UNSIGNED) > 0
- );
- column.decimal = () => packet.readDecimalLengthEncoded(opts.bigNumberStrings);
- column.date = () => packet.readDateTime(opts);
- column.geometry = () => {
- return column.readGeometry();
- };
- }
- readCastValue(index, column, opts, connOpts, packet) {
- this.castTextWrapper(column, opts, connOpts, packet);
- return opts.typeCast(
- column,
- this.readRowData.bind(this, index, column, opts, connOpts, packet)
- );
- }
- /**
- * Read row data.
- *
- * @param index current data index in row
- * @param column associate metadata
- * @param opts query options
- * @param connOpts connection options
- * @param packet row packet
- * @returns {*} data
- */
- readRowData(index, column, opts, connOpts, packet) {
- switch (column.columnType) {
- case FieldType.TINY:
- case FieldType.SHORT:
- case FieldType.LONG:
- case FieldType.INT24:
- case FieldType.YEAR:
- return packet.readIntLengthEncoded();
- case FieldType.FLOAT:
- case FieldType.DOUBLE:
- return packet.readFloatLengthCoded();
- case FieldType.LONGLONG:
- return packet.readLongLengthEncoded(
- opts.supportBigInt,
- opts.supportBigNumbers,
- opts.bigNumberStrings,
- (column.flags & FieldDetail.UNSIGNED) > 0
- );
- case FieldType.DECIMAL:
- case FieldType.NEWDECIMAL:
- return packet.readDecimalLengthEncoded(opts.bigNumberStrings);
- case FieldType.DATE:
- if (opts.dateStrings) {
- return packet.readAsciiStringLengthEncoded();
- }
- return packet.readDate();
- case FieldType.DATETIME:
- case FieldType.TIMESTAMP:
- if (opts.dateStrings) {
- return packet.readAsciiStringLengthEncoded();
- }
- return packet.readDateTime(opts);
- case FieldType.TIME:
- return packet.readAsciiStringLengthEncoded();
- case FieldType.GEOMETRY:
- return packet.readGeometry(column.dataTypeName);
- case FieldType.JSON:
- //for mysql only => parse string as JSON object
- return JSON.parse(packet.readStringLengthEncoded('utf8'));
- default:
- if (column.dataTypeFormat && column.dataTypeFormat === 'json' && opts.autoJsonMap) {
- return JSON.parse(packet.readStringLengthEncoded('utf8'));
- }
- if (column.collation.index === 63) {
- return packet.readBufferLengthEncoded();
- }
- const string = packet.readStringLength();
- if (column.flags & 2048) {
- //SET
- return string == null ? null : string === '' ? [] : string.split(',');
- }
- return string;
- }
- }
- }
- function getDatePartQuote(year, mon, day, hour, min, sec, ms) {
- //return 'YYYY-MM-DD HH:MM:SS' datetime format
- //see https://mariadb.com/kb/en/library/datetime/
- return (
- "'" +
- (year > 999 ? year : year > 99 ? '0' + year : year > 9 ? '00' + year : '000' + year) +
- '-' +
- (mon < 10 ? '0' : '') +
- mon +
- '-' +
- (day < 10 ? '0' : '') +
- day +
- ' ' +
- (hour < 10 ? '0' : '') +
- hour +
- ':' +
- (min < 10 ? '0' : '') +
- min +
- ':' +
- (sec < 10 ? '0' : '') +
- sec +
- '.' +
- (ms > 99 ? ms : ms > 9 ? '0' + ms : '00' + ms) +
- "'"
- );
- }
- function getLocalDate(date, opts) {
- const year = date.getFullYear();
- const mon = date.getMonth() + 1;
- const day = date.getDate();
- const hour = date.getHours();
- const min = date.getMinutes();
- const sec = date.getSeconds();
- const ms = date.getMilliseconds();
- return getDatePartQuote(year, mon, day, hour, min, sec, ms);
- }
- function getUtcDate(date, opts) {
- const year = date.getUTCFullYear();
- const mon = date.getUTCMonth() + 1;
- const day = date.getUTCDate();
- const hour = date.getUTCHours();
- const min = date.getUTCMinutes();
- const sec = date.getUTCSeconds();
- const ms = date.getUTCMilliseconds();
- return getDatePartQuote(year, mon, day, hour, min, sec, ms);
- }
- function getTimezoneDate(date, opts) {
- if (date.getMilliseconds() != 0) {
- return moment.tz(date, opts.tz).format("'YYYY-MM-DD HH:mm:ss.SSS'");
- }
- return moment.tz(date, opts.tz).format("'YYYY-MM-DD HH:mm:ss'");
- }
- module.exports = CommonText;
- module.exports.getTimezoneDate = getTimezoneDate;
- module.exports.getUtcDate = getUtcDate;
- module.exports.getLocalDate = getLocalDate;
|