2018-10-24 21:42:33 +08:00
|
|
|
'use strict';
|
|
|
|
|
2015-05-13 19:00:01 +08:00
|
|
|
var step = require('step');
|
|
|
|
var PSQL = require('cartodb-psql');
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
function PostgresFormat (id) {
|
2014-07-31 01:36:25 +08:00
|
|
|
this.id = id;
|
|
|
|
}
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2014-07-31 01:43:43 +08:00
|
|
|
PostgresFormat.prototype = {
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
getQuery: function (sql/*, options */) {
|
|
|
|
return sql;
|
|
|
|
},
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
getContentType: function () {
|
|
|
|
return this._contentType;
|
|
|
|
},
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
getFileExtension: function () {
|
|
|
|
return this.id;
|
|
|
|
}
|
2013-05-27 17:21:56 +08:00
|
|
|
|
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.handleQueryRow = function (row, result) {
|
2014-07-31 01:48:57 +08:00
|
|
|
result.addRow(row);
|
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.handleQueryRowWithSkipFields = function (row, result) {
|
2014-07-31 01:36:25 +08:00
|
|
|
var sf = this.opts.skipfields;
|
2019-12-24 01:19:08 +08:00
|
|
|
for (var j = 0; j < sf.length; ++j) {
|
2014-07-31 01:48:57 +08:00
|
|
|
delete row[sf[j]];
|
2013-05-29 20:36:31 +08:00
|
|
|
}
|
2014-07-31 08:17:07 +08:00
|
|
|
this.handleQueryRow(row, result);
|
2013-05-29 20:36:31 +08:00
|
|
|
};
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.handleNotice = function (msg, result) {
|
|
|
|
if (!result.notices) {
|
2015-05-13 19:00:01 +08:00
|
|
|
result.notices = [];
|
|
|
|
}
|
2019-12-24 01:19:08 +08:00
|
|
|
for (var i = 0; i < msg.length; i++) {
|
2014-07-31 08:17:07 +08:00
|
|
|
result.notices.push(msg[i]);
|
|
|
|
}
|
2013-11-19 00:01:06 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.handleQueryEnd = function (result) {
|
|
|
|
this.queryCanceller = undefined;
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
if (this.error) {
|
|
|
|
this.callback(this.error);
|
|
|
|
return;
|
2013-09-26 19:26:45 +08:00
|
|
|
}
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
if (this.opts.profiler) {
|
|
|
|
this.opts.profiler.done('gotRows');
|
|
|
|
}
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
this.opts.total_time = (Date.now() - this.start_time) / 1000;
|
|
|
|
|
|
|
|
// Drop field description for skipped fields
|
|
|
|
if (this.hasSkipFields) {
|
|
|
|
var sf = this.opts.skipfields;
|
|
|
|
var newfields = [];
|
|
|
|
for (var j = 0; j < result.fields.length; ++j) {
|
|
|
|
var f = result.fields[j];
|
|
|
|
if (sf.indexOf(f.name) === -1) {
|
|
|
|
newfields.push(f);
|
|
|
|
}
|
2018-11-08 01:05:39 +08:00
|
|
|
}
|
2019-12-24 01:19:08 +08:00
|
|
|
result.fields = newfields;
|
|
|
|
}
|
2013-05-27 17:21:56 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
var that = this;
|
|
|
|
|
|
|
|
step(
|
|
|
|
function packageResult () {
|
|
|
|
that.transform(result, that.opts, this);
|
|
|
|
},
|
|
|
|
function sendResults (err, out) {
|
|
|
|
if (err) {
|
|
|
|
throw err;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return to browser
|
|
|
|
if (out) {
|
|
|
|
if (that.opts.beforeSink) {
|
|
|
|
that.opts.beforeSink();
|
|
|
|
}
|
|
|
|
that.opts.sink.send(out);
|
|
|
|
} else {
|
|
|
|
console.error('No output from transform, doing nothing ?!');
|
|
|
|
}
|
|
|
|
},
|
|
|
|
function errorHandle (err) {
|
|
|
|
that.callback(err);
|
2013-05-29 20:36:31 +08:00
|
|
|
}
|
2019-12-24 01:19:08 +08:00
|
|
|
);
|
2013-05-27 17:21:56 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.sendResponse = function (opts, callback) {
|
|
|
|
if (this.callback) {
|
|
|
|
callback(new Error('Invalid double call to .sendResponse on a pg formatter'));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this.callback = callback;
|
|
|
|
this.opts = opts;
|
2013-05-29 20:36:31 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
this.hasSkipFields = opts.skipfields.length;
|
2014-07-31 01:36:25 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
var sql = this.getQuery(opts.sql, {
|
|
|
|
gn: opts.gn,
|
|
|
|
dp: opts.dp,
|
|
|
|
skipfields: opts.skipfields
|
|
|
|
});
|
2013-05-29 20:36:31 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
var that = this;
|
2013-05-29 20:36:31 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
this.start_time = Date.now();
|
2013-05-29 20:36:31 +08:00
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
this.client = new PSQL(opts.dbopts);
|
|
|
|
this.client.eventedQuery(sql, function (err, query, queryCanceller) {
|
|
|
|
that.queryCanceller = queryCanceller;
|
|
|
|
if (err) {
|
|
|
|
callback(err);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (that.opts.profiler) {
|
|
|
|
that.opts.profiler.done('eventedQuery');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (that.hasSkipFields) {
|
|
|
|
query.on('row', that.handleQueryRowWithSkipFields.bind(that));
|
|
|
|
} else {
|
|
|
|
query.on('row', that.handleQueryRow.bind(that));
|
|
|
|
}
|
|
|
|
query.on('end', that.handleQueryEnd.bind(that));
|
|
|
|
query.on('error', function (err) {
|
|
|
|
that.error = err;
|
|
|
|
if (err.message && err.message.match(/row too large, was \d* bytes/i)) {
|
|
|
|
return console.error(JSON.stringify({
|
|
|
|
username: opts.username,
|
|
|
|
type: 'row_size_limit_exceeded',
|
|
|
|
error: err.message
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
that.handleQueryEnd();
|
|
|
|
});
|
|
|
|
query.on('notice', function (msg) {
|
|
|
|
that.handleNotice(msg, query._result);
|
|
|
|
});
|
|
|
|
});
|
2013-05-29 20:36:31 +08:00
|
|
|
};
|
|
|
|
|
2019-12-24 01:19:08 +08:00
|
|
|
PostgresFormat.prototype.cancel = function () {
|
2014-06-02 20:48:38 +08:00
|
|
|
if (this.queryCanceller) {
|
|
|
|
this.queryCanceller.call();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-07-31 01:43:43 +08:00
|
|
|
module.exports = PostgresFormat;
|