tdengine-client
Version:
A Node.js connector for TDengine.
958 lines (815 loc) • 32.6 kB
JavaScript
/**
* C Interface with TDengine Module
* @module CTaosInterface
*/
const ref = require('ref-napi');
const os = require('os');
const ffi = require('ffi-napi');
const FieldTypes = require('./constants');
const errors = require('./error');
const _ = require('lodash')
const TaosObjects = require('./taosobjects');
const libtaos = require('./taoslib');
const AppendRun = require('./uft8');
const { TaosMultiBind } = require('./taosMultiBind');
module.exports = CTaosInterface;
const TAOSFIELD = {
NAME_LENGTH: 65,
TYPE_OFFSET: 65,
BYTES_OFFSET: 68,
STRUCT_SIZE: 72,
}
function convertTimestamp(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = (numOfRows + ((1 << 3) - 1)) >> 3;
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt64LE();
res.push(new TaosObjects.TaosTimestamp(data, precision));
}
offset = offset + nBytes;
}
return res;
}
function convertBool(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt8();
res.push(data == 1 ? true : false);
}
offset = offset + nBytes;
}
return res;
}
function convertTinyint(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt8();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertTinyintUnsigned(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readUInt8();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertSmallint(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt16LE();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertSmallintUnsigned(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readUInt16LE();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertInt(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readUInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt32LE();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertIntUnsigned(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readUInt32LE();
res.push(data);
}
offset = offset + nBytes;
}
return res;
}
function convertBigint(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readInt64LE();
res.push(BigInt(data));
}
offset = offset + nBytes;
}
return res;
}
function convertBigintUnsigned(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readUInt64LE();
res.push(BigInt(data));
}
offset = offset + nBytes;
}
return res;
}
function convertFloat(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readFloatLE().toFixed(5);
res.push(parseFloat(data));
}
offset = offset + nBytes;
}
return res;
}
function convertDouble(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let bitMapSize = Math.ceil(numOfRows / 8.0);
let bitMapBuf = ref.reinterpret(colHeadPtr, bitMapSize, 0);
offset = bitMapSize;
for (let i = 0; i < numOfRows; i++) {
let byteIndex = i >> 3
let bitWiseOffset = 7 - (i & 7)
let ifNullByte = bitMapBuf.readInt8(byteIndex);
let ifNullFlag = (ifNullByte & (1 << bitWiseOffset)) >> bitWiseOffset;
if (ifNullFlag == 1) {
res.push(null);
} else {
let colDataBuf = ref.reinterpret(colHeadPtr, nBytes, offset);
let data = colDataBuf.readDoubleLE().toFixed(16);
// console.log("convertDouble buff:",JSON.stringify(colDataBuf))
// console.log("convertDouble data:",data,i)
res.push(parseFloat(data));
}
offset = offset + nBytes;
}
return res;
}
function convertBinary(colHeadPtr, numOfRows, nbytes = 0, offset = 0, precision = 0) {
let res = [];
let int16Size = ref.sizeof.int16;
let intSize = ref.sizeof.int;
let offsetArrLength = intSize * numOfRows;
let offsetArrBuff = ref.reinterpret(colHeadPtr, offsetArrLength, 0);
for (let i = 0; i < numOfRows; i++) {
let offset = offsetArrBuff.readInt32LE(i * intSize);
if (offset == -1) {
res.push(null)
} else {
let dataLengthBuff = ref.reinterpret(colHeadPtr, int16Size, offsetArrLength + offset);
let dataLength = dataLengthBuff.readInt16LE()
let dataBuff = ref.reinterpret(colHeadPtr, dataLength, offsetArrLength + offset + int16Size);
let data = dataBuff.toString('utf8')
res.push(data)
}
}
return res;
}
function convertNchar(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let int16Size = ref.sizeof.int16;
let intSize = ref.sizeof.int32;
let offsetArrLength = intSize * numOfRows;
let offsetArrBuff = ref.reinterpret(colHeadPtr, offsetArrLength, 0);
for (let i = 0; i < numOfRows; i++) {
let offset = offsetArrBuff.readInt32LE(i * intSize);
if (offset == -1) {
res.push(null)
} else {
let dataLengthBuff = ref.reinterpret(colHeadPtr, int16Size, offsetArrLength + offset);
let dataLength = dataLengthBuff.readInt16LE()
let stringLength = dataLength / 4;
let result = '';
for (let j = 0; j < stringLength; j++) {
let dataBuff = ref.reinterpret(colHeadPtr, 4, offsetArrLength + offset + int16Size + j * 4);
let str = dataBuff.readUInt32LE(0);
result += AppendRun(str)
}
res.push(result);
}
}
return res;
}
function convertJsonTag(colHeadPtr, numOfRows, nBytes = 0, offset = 0, precision = 0) {
let res = [];
let int16Size = ref.sizeof.int16;
let intSize = ref.sizeof.int;
let offsetArrLength = intSize * numOfRows;
let offsetArrBuff = ref.reinterpret(colHeadPtr, offsetArrLength, 0);
for (let i = 0; i < numOfRows; i++) {
let offset = offsetArrBuff.readInt32LE(i * intSize);
if (offset == -1) {
res.push(null)
} else {
let dataLengthBuff = ref.reinterpret(colHeadPtr, int16Size, offsetArrLength + offset);
let dataLength = dataLengthBuff.readInt16LE()
let dataBuff = ref.reinterpret(colHeadPtr, dataLength, offsetArrLength + offset + int16Size);
let data = dataBuff.toString('utf8')
res.push(data)
}
}
return res;
}
// Object with all the relevant converters from pblock data to javascript readable data
let convertFunctions = {
[FieldTypes.C_BOOL]: convertBool,
[FieldTypes.C_TINYINT]: convertTinyint,
[FieldTypes.C_SMALLINT]: convertSmallint,
[FieldTypes.C_INT]: convertInt,
[FieldTypes.C_BIGINT]: convertBigint,
[FieldTypes.C_FLOAT]: convertFloat,
[FieldTypes.C_DOUBLE]: convertDouble,
[FieldTypes.C_BINARY]: convertBinary,
[FieldTypes.C_TIMESTAMP]: convertTimestamp,
[FieldTypes.C_NCHAR]: convertNchar,
[FieldTypes.C_TINYINT_UNSIGNED]: convertTinyintUnsigned,
[FieldTypes.C_SMALLINT_UNSIGNED]: convertSmallintUnsigned,
[FieldTypes.C_INT_UNSIGNED]: convertIntUnsigned,
[FieldTypes.C_BIGINT_UNSIGNED]: convertBigintUnsigned,
[FieldTypes.C_JSON_TAG]: convertJsonTag,
}
/**
*
* @param {Object} config - Configuration options for the interface
* @return {CTaosInterface}
* @class CTaosInterface
* @classdesc The CTaosInterface is the interface through which Node.JS communicates data back and forth with TDengine. It is not advised to
* access this class directly and use it unless you understand what these functions do.
*/
function CTaosInterface(config = null, pass = false) {
if (pass == false) {
if (config == null) {
this._config = ref.alloc(ref.types.char_ptr, ref.NULL);
}
else {
try {
this._config = ref.allocCString(config);
}
catch (err) {
throw "Attribute Error: config is expected as a str";
}
}
if (config != null) {
libtaos.taos_options(3, this._config);
}
}
return this;
}
CTaosInterface.prototype.config = function config() {
return this._config;
}
CTaosInterface.prototype.connect = function connect(host = null, user = "root", password = "taosdata", db = null, port = 0) {
let _host, _user, _password, _db, _port;
try {
_host = host != null ? ref.allocCString(host) : ref.NULL;
}
catch (err) {
throw "Attribute Error: host is expected as a str";
}
try {
_user = ref.allocCString(user)
}
catch (err) {
throw "Attribute Error: user is expected as a str";
}
try {
_password = ref.allocCString(password);
}
catch (err) {
throw "Attribute Error: password is expected as a str";
}
try {
_db = db != null ? ref.allocCString(db) : ref.NULL;
}
catch (err) {
throw "Attribute Error: db is expected as a str";
}
try {
_port = ref.alloc(ref.types.int, port);
}
catch (err) {
throw TypeError("port is expected as an int")
}
let connection = libtaos.taos_connect(_host, _user, _password, _db, _port);
if (ref.isNull(connection)) {
throw new errors.TDError('Failed to connect to TDengine');
}
else {
console.log('Successfully connected to TDengine');
}
return connection;
}
CTaosInterface.prototype.close = function close(connection) {
libtaos.taos_close(connection);
console.log("Connection is closed");
}
CTaosInterface.prototype.query = function query(connection, sql) {
return libtaos.taos_query(connection, ref.allocCString(sql));
}
CTaosInterface.prototype.affectedRows = function affectedRows(result) {
return libtaos.taos_affected_rows(result);
}
CTaosInterface.prototype.useResult = function useResult(result) {
let fields = [];
let pfields = this.fetchFields(result);
if (ref.isNull(pfields) == false) {
pfields = ref.reinterpret(pfields, this.fieldsCount(result) * TAOSFIELD.STRUCT_SIZE, 0);
for (let i = 0; i < pfields.length; i += TAOSFIELD.STRUCT_SIZE) {
fields.push({
name: ref.readCString(ref.reinterpret(pfields, TAOSFIELD.NAME_LENGTH, i)),
type: pfields[i + TAOSFIELD.TYPE_OFFSET],
bytes: pfields[i + TAOSFIELD.BYTES_OFFSET] + pfields[i + TAOSFIELD.BYTES_OFFSET + 1] * 256
})
}
}
return fields;
}
CTaosInterface.prototype.fetchRawBlock = function fetchRawBlock(taosRes) {
var numOfRowPtr = ref.alloc('int *');
var pDataPtr = ref.alloc('void **');
let code = libtaos.taos_fetch_raw_block(taosRes, numOfRowPtr, pDataPtr);
if (code == 0) {
let numOfRows = numOfRowPtr.readInt32LE();
let pData = ref.deref(pDataPtr);
let numOfFields = libtaos.taos_field_count(taosRes);
let precision = libtaos.taos_result_precision(taosRes);
let fields = this.useResult(taosRes);
let bitMapSize = Math.ceil(numOfRows / 8.0);
let offsetArrLength = ref.sizeof.int32 * numOfRows;
let blocks = new Array(numOfFields);
blocks.fill(null);
// print block raw
// let blockLength = ref.reinterpret(pData, ref.sizeof.int,4).readInt32LE();
// console.log(blockLength)
// let content_str=''
// for(let i = 0; i<blockLength;i++){
// let byteContent = ref.reinterpret(pData,ref.sizeof.byte,i).readUInt8()
// content_str += byteContent +"\t"
// if((i+1)%4 == 0){
// content_str +="\n"
// }
// }
// console.log(content_str)
// offset pData
let offsetBeforeLengthArr = (4 * 5) + 8 + (4 + 1) * numOfFields;
var lengthArraySize = 4 * numOfFields;
let offsetForColData = offsetBeforeLengthArr + lengthArraySize;
// read column after column
if (numOfRows > 0) {
for (let i = 0; i < numOfFields; i++) {
let lengthPtr = ref.reinterpret(pData, ref.sizeof.int, offsetBeforeLengthArr + (i * 4));
let length = lengthPtr.readInt32LE();
if (!convertFunctions[fields[i]['type']]) {
throw new errors.DatabaseError("Invalid data type returned from database");
} else if (fields[i]['type'] == 8 || fields[i]['type'] == 10 || fields[i]['type'] == 15) {
let colHeadPtr = ref.reinterpret(pData, length + offsetArrLength, offsetForColData)
blocks[i] = convertFunctions[fields[i]['type']](colHeadPtr, numOfRows, fields[i].bytes, 0, precision);
offsetForColData = offsetForColData + offsetArrLength + length;
} else {
let colHeadPtr = ref.reinterpret(pData, length + bitMapSize, offsetForColData)
blocks[i] = convertFunctions[fields[i]['type']](colHeadPtr, numOfRows, fields[i].bytes, 0, precision);
offsetForColData = offsetForColData + bitMapSize + length;
}
}
}
return { blocks: blocks, num_of_rows: Math.abs(numOfRows) }
} else {
throw new OperationalError(`${libtaos.taos_errstr(taosRes)} ,${code}`);
}
}
CTaosInterface.prototype.freeResult = function freeResult(result) {
libtaos.taos_free_result(result);
result = null;
}
/** Number of fields returned in this result handle, must use with async */
CTaosInterface.prototype.numFields = function numFields(result) {
return libtaos.taos_num_fields(result);
}
// Fetch fields count by connection, the latest query
CTaosInterface.prototype.fieldsCount = function fieldsCount(result) {
return libtaos.taos_field_count(result);
}
CTaosInterface.prototype.fetchFields = function fetchFields(result) {
return libtaos.taos_fetch_fields(result);
}
CTaosInterface.prototype.errno = function errno(result) {
return libtaos.taos_errno(result);
}
CTaosInterface.prototype.errStr = function errStr(result) {
return ref.readCString(libtaos.taos_errstr(result));
}
// Async
CTaosInterface.prototype.query_a = function query_a(connection, sql, callback, param = ref.ref(ref.NULL)) {
// void taos_query_a(TAOS *taos, char *sqlstr, void (*fp)(void *param, TAOS_RES *, int), void *param)
callback = ffi.Callback(ref.types.void, [ref.types.void_ptr, ref.types.void_ptr, ref.types.int], callback);
libtaos.taos_query_a(connection, ref.allocCString(sql), callback, param);
return param;
}
/** Asynchrnously fetches the next block of rows. Wraps callback and transfers a 4th argument to the cursor, the row data as blocks in javascript form
* Note: This isn't a recursive function, in order to fetch all data either use the TDengine cursor object, TaosQuery object, or implement a recrusive
* function yourself using the libtaos.taos_fetch_raw_block_a function
*/
CTaosInterface.prototype.fetch_raw_block_a = function fetch_raw_block_a(taosRes, callback, param = ref.ref(ref.NULL)) {
var cti = this;
var fetchRawBlock_a_callback = function (param2, taosRes2, numOfRows2) {
let fields = cti.fetchFields_a(taosRes2);
let precision = libtaos.taos_result_precision(taosRes2);
let fieldLengthArr = [];
let fieldLengthPtr = libtaos.taos_fetch_lengths(taosRes2);
if (ref.isNull(fieldLengthPtr) == false) {
for (let i = 0; i < fields.length; i++) {
let fieldLengthBuf = ref.reinterpret(fieldLengthPtr, ref.sizeof.int32, i * ref.sizeof.int32);
let fieldLength = ref.get(fieldLengthBuf, 0, ref.types.int32);
fieldLengthArr.push(fieldLength);
}
}
// =====logic same as fetch_raw_block
// parse raw block from here.
let pData = libtaos.taos_get_raw_block(taosRes2);
let numOfRows = numOfRows2;
let numOfFields = libtaos.taos_field_count(taosRes2);
let bitMapSize = (numOfRows + ((1 << 3) - 1)) >> 3;
let offsetArrLength = ref.sizeof.int32 * numOfRows;
let blocks = new Array(numOfFields);
blocks.fill(null);
// offset pData
let offsetBeforeLengthArr = (4 * 5) + 8 + (4 + 1) * numOfFields;
var lengthArraySize = 4 * numOfFields;
let offsetForColData = offsetBeforeLengthArr + lengthArraySize;
// read column after column
for (let i = 0; i < numOfFields; i++) {
let lengthPtr = ref.reinterpret(pData, ref.sizeof.int, offsetBeforeLengthArr + (i * 4));
let length = lengthPtr.readInt32LE();
if (!convertFunctions[fields[i]['type']]) {
throw new errors.DatabaseError("Invalid data type returned from database");
} else if (fields[i]['type'] == 8 || fields[i]['type'] == 10 || fields[i]['type'] == 15) {
let colHeadPtr = ref.reinterpret(pData, length + offsetArrLength, offsetForColData)
blocks[i] = convertFunctions[fields[i]['type']](colHeadPtr, numOfRows, fields[i].bytes, 0, precision);
offsetForColData = offsetForColData + offsetArrLength + length;
} else {
let colHeadPtr = ref.reinterpret(pData, length + bitMapSize, offsetForColData)
blocks[i] = convertFunctions[fields[i]['type']](colHeadPtr, numOfRows, fields[i].bytes, 0, precision);
offsetForColData = offsetForColData + bitMapSize + length;
}
}
callback(param2, taosRes2, numOfRows2, blocks);
}
var fetchRawBlock_a_callback = ffi.Callback(ref.types.void, [ref.types.void_ptr, ref.types.void_ptr, ref.types.int], fetchRawBlock_a_callback);
libtaos.taos_fetch_raw_block_a(taosRes, fetchRawBlock_a_callback, param)
}
// Used to parse the TAO_RES retrieved in taos_fetch_row_a()'s callback
// block after block.
CTaosInterface.prototype.get_raw_block = function get_raw_block(taosRes) {
return libtaos.get_raw_block(taosRes)
}
// Fetch field meta data by result handle
CTaosInterface.prototype.fetchFields_a = function fetchFields_a(result) {
let pfields = this.fetchFields(result);
let pfieldscount = this.numFields(result);
let fields = [];
if (ref.isNull(pfields) == false) {
pfields = ref.reinterpret(pfields, pfieldscount * TAOSFIELD.STRUCT_SIZE, 0);
for (let i = 0; i < pfields.length; i += TAOSFIELD.STRUCT_SIZE) {
fields.push({
name: ref.readCString(ref.reinterpret(pfields, TAOSFIELD.NAME_LENGTH, i)),
type: pfields[i + TAOSFIELD.TYPE_OFFSET],
bytes: pfields[i + TAOSFIELD.BYTES_OFFSET] + pfields[i + TAOSFIELD.BYTES_OFFSET + 1] * 256
})
}
}
return fields;
}
// Stop a query by result handle
CTaosInterface.prototype.stopQuery = function stopQuery(result) {
if (result != null) {
libtaos.taos_stop_query(result);
}
else {
throw new errors.ProgrammingError("No result handle passed to stop query");
}
}
CTaosInterface.prototype.getServerInfo = function getServerInfo(connection) {
return ref.readCString(libtaos.taos_get_server_info(connection));
}
CTaosInterface.prototype.getClientInfo = function getClientInfo() {
return ref.readCString(libtaos.taos_get_client_info());
}
//Schemaless insert API
/**
* TAOS* taos, char* lines[], int numLines, int protocol,int precision)
* using taos_errstr get error info, taos_errno get error code. Remember
* to release taos_res, otherwise will lead memory leak.
* TAOS schemaless insert api
* @param {*} connection a valid database connection
* @param {*} lines string data, which satisfied with line protocol
* @param {*} numLines number of rows in param lines.
* @param {*} protocol Line protocol, enum type (0,1,2,3),indicate different line protocol
* @param {*} precision timestamp precision in lines, enum type (0,1,2,3,4,5,6)
* @returns TAOS_RES
*
*/
CTaosInterface.prototype.schemalessInsert = function schemalessInsert(connection, lines, protocal, precision) {
let _numLines = null;
let _lines = null;
if (_.isString(lines)) {
_numLines = 1;
_lines = Buffer.alloc(_numLines * ref.sizeof.pointer);
ref.set(_lines, 0, ref.allocCString(lines), ref.types.char_ptr);
}
else if (_.isArray(lines)) {
_numLines = lines.length;
_lines = Buffer.alloc(_numLines * ref.sizeof.pointer);
for (let i = 0; i < _numLines; i++) {
ref.set(_lines, i * ref.sizeof.pointer, ref.allocCString(lines[i]), ref.types.char_ptr)
}
}
else {
throw new errors.InterfaceError("Unsupport lines input")
}
return libtaos.taos_schemaless_insert(connection, _lines, _numLines, protocal, precision);
}
//stmt APIs
/**
* init a TAOS_STMT object for later use.it should be freed with stmtClose.
* @param {*} connection valid taos connection
* @returns Not NULL returned for success, and NULL for failure.
*
*/
CTaosInterface.prototype.stmtInit = function stmtInit(connection) {
return libtaos.taos_stmt_init(connection)
}
/**
* prepare a sql statement,'sql' should be a valid INSERT/SELECT statement, 'length' is not used.
* @param {*} stmt
* @param {string} sql a valid INSERT/SELECT statement
* @param {ulong} length not used
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtPrepare = function stmtPrepare(stmt, sql, length) {
return libtaos.taos_stmt_prepare(stmt, ref.allocCString(sql), 0);
}
/**
* For INSERT only. Used to bind table name as a parmeter for the input stmt object.
* @param {*} stmt could be the value returned by 'stmtInit',
* that may be a valid object or NULL.
* @param {TaosMultiBind} tableName target table name you want to bind
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtSetTbname = function stmtSetTbname(stmt, tableName) {
return libtaos.taos_stmt_set_tbname(stmt, ref.allocCString(tableName));
}
/**
* For INSERT only.
* Set a table name for binding table name as parameter and tag values for all tag parameters.
* @param {*} stmt could be the value returned by 'stmtInit', that may be a valid object or NULL.
* @param {*} tableName use to set target table name
* @param {TaosMultiBind} tags use to set tag value for target table.
* @returns
*/
CTaosInterface.prototype.stmtSetTbnameTags = function stmtSetTbnameTags(stmt, tableName, tags) {
return libtaos.taos_stmt_set_tbname_tags(stmt, ref.allocCString(tableName), tags);
}
/**
* For INSERT only.
* Set a table name for binding table name as parameter. Only used for binding all tables
* in one stable, user application must call 'loadTableInfo' API to load all table
* meta before calling this API. If the table meta is not cached locally, it will return error.
* @param {*} stmt could be the value returned by 'StmtInit', that may be a valid object or NULL.
* @param {*} subTableName table name which is belong to an stable
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtSetSubTbname = function stmtSetSubTbname(stmt, subTableName) {
return libtaos.taos_stmt_set_sub_tbname(stmt, subTableName);
}
/**
* Bind a single column's data, INTERNAL used and for INSERT only.
* @param {*} stmt could be the value returned by 'stmtInit', that may be a valid object or NULL.
* @param {TaosMultiBind} mbind points to a column's data which could be the one or more lines.
* @param {*} colIndex the column's index in prepared sql statement, it starts from 0.
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtBindSingleParamBatch = function stmtBindSingleParamBatch(stmt, mbind, colIndex) {
return libtaos.taos_stmt_bind_single_param_batch(stmt, mbind.ref(), colIndex);
}
/**
* For INSERT only.
* Bind one or multiple lines data.
* @param {*} stmt could be the value returned by 'stmtInit',
* that may be a valid object or NULL.
* @param {*} mbinds Points to an array contains one or more lines data.The item
* number and sequence should keep consistence with columns
* n sql statement.
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtBindParamBatch = function stmtBindParamBatch(stmt, mbinds) {
return libtaos.taos_stmt_bind_param_batch(stmt, mbinds);
}
/**
* add all current bound parameters to batch process, for INSERT only.
* Must be called after each call to bindParam/bindSingleParamBatch,
* or all columns binds for one or more lines with bindSingleParamBatch. User
* application can call any bind parameter API again to bind more data lines after calling
* to this API.
* @param {*} stmt
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.addBatch = function addBatch(stmt) {
return libtaos.taos_stmt_add_batch(stmt);
}
/**
* actually execute the INSERT/SELECT sql statement. User application can continue
* to bind new data after calling to this API.
* @param {*} stmt
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.stmtExecute = function stmtExecute(stmt) {
return libtaos.taos_stmt_execute(stmt);
}
/**
* For SELECT only,getting the query result.
* User application should free it with API 'FreeResult' at the end.
* @param {*} stmt could be the value returned by 'stmtInit', that may be a valid object or NULL.
* @returns Not NULL for success, NULL for failure.
*/
CTaosInterface.prototype.stmtUseResult = function stmtUseResult(stmt) {
return libtaos.taos_stmt_use_result(stmt);
}
/**
* user application call this API to load all tables meta info.
* This method must be called before stmtSetSubTbname(IntPtr stmt, string name);
* @param {*} taos taos connection
* @param {*} tableList tables need to load meta info are form in an array
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.loadTableInfo = function loadTableInfo(taos, tableList) {
let _tableListBuf = Buffer.alloc(ref.sizeof.pointer);
let _listStr = tableList.toString();
if ((_.isString(tableList)) || (_.isArray(tableList))) {
ref.set(_tableListBuf, 0, ref.allocCString(_listStr), ref.types.char_ptr);
return libtaos.taos_load_table_info(taos, _tableListBuf);
} else {
throw new errors.InterfaceError("Unspport tableLis input");
}
}
/**
* Close STMT object and free resources.
* @param {*} stmt could be the value returned by 'stmtInit', that may be a valid object or NULL.
* @returns 0 for success, non-zero for failure.
*/
CTaosInterface.prototype.closeStmt = function closeStmt(stmt) {
return libtaos.taos_stmt_close(stmt);
}
/**
* Get detail error message when got failure for any stmt API call.
* If not failure, the result returned by this API is unknown.
* @param {*} stmt Could be the value returned by 'stmtInit', that may be a valid object or NULL.
* @returns error string
*/
CTaosInterface.prototype.stmtErrStr = function stmtErrStr(stmt) {
return ref.readCString(libtaos.taos_stmt_errstr(stmt));
}
// CTaosInterface.prototype.getServerStatus = function getServerStatus(fqdn,port){
// const maxLen = 512;
// let detailPtr = ref.ref(Buffer.alloc(maxLen));
// let statusCode = libtaos.taos_check_server_status(fqdn,port,detailPtr,maxLen);
// let detail = ref.readCString(detailPtr);
// if (statusCode == 0){
// return "[TSDB_SRV_STATUS_UNAVAILABLE]:"+detail;
// }else if(statusCode == 1){
// return "[TSDB_SRV_STATUS_NETWORK_OK]:"+detail;
// }else if(statusCode == 2){
// return "[TSDB_SRV_STATUS_NETWORK_OK]:"+detail;
// }else if(statusCode == 3){
// return "[TSDB_SRV_STATUS_SERVICE_DEGRADED]:"+detail;
// }else if(statusCode == 4){
// return "[TSDB_SRV_STATUS_EXTING]:"+detail;
// }
// }