TSDBJNIConnector.c 23.1 KB
Newer Older
H
hzcheng 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
/*
 * Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
 *
 * This program is free software: you can use, redistribute, and/or modify
 * it under the terms of the GNU Affero General Public License, version 3
 * or later ("AGPL"), as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */

H
hjxilinx 已提交
16
#include "os.h"
H
hzcheng 已提交
17
#include "taos.h"
H
Haojun Liao 已提交
18
#include "tlog.h"
H
hzcheng 已提交
19
#include "tscUtil.h"
H
hjxilinx 已提交
20
#include "tsclient.h"
H
hzcheng 已提交
21

H
Haojun Liao 已提交
22 23
#include "com_taosdata_jdbc_TSDBJNIConnector.h"

24 25
#define jniFatal(...) { if (jniDebugFlag & DEBUG_FATAL) { taosPrintLog("JNI FATAL ", tscEmbedded ? 255 : jniDebugFlag, __VA_ARGS__); }}
#define jniError(...) { if (jniDebugFlag & DEBUG_ERROR) { taosPrintLog("JNI ERROR ", tscEmbedded ? 255 : jniDebugFlag, __VA_ARGS__); }}
S
Shengliang Guan 已提交
26 27 28 29
#define jniWarn(...)  { if (jniDebugFlag & DEBUG_WARN)  { taosPrintLog("JNI WARN ", tscEmbedded ? 255 : jniDebugFlag, __VA_ARGS__); }}
#define jniInfo(...)  { if (jniDebugFlag & DEBUG_INFO)  { taosPrintLog("JNI ", tscEmbedded ? 255 : jniDebugFlag, __VA_ARGS__); }}
#define jniDebug(...) { if (jniDebugFlag & DEBUG_DEBUG) { taosPrintLog("JNI ", jniDebugFlag, __VA_ARGS__); }}
#define jniTrace(...) { if (jniDebugFlag & DEBUG_TRACE) { taosPrintLog("JNI ", jniDebugFlag, __VA_ARGS__); }}
30

H
hzcheng 已提交
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
int __init = 0;

JavaVM *g_vm = NULL;

jclass    g_arrayListClass;
jmethodID g_arrayListConstructFp;
jmethodID g_arrayListAddFp;

jclass    g_metadataClass;
jmethodID g_metadataConstructFp;
jfieldID  g_metadataColtypeField;
jfieldID  g_metadataColnameField;
jfieldID  g_metadataColsizeField;
jfieldID  g_metadataColindexField;

jclass    g_rowdataClass;
jmethodID g_rowdataConstructor;
jmethodID g_rowdataClearFp;
jmethodID g_rowdataSetBooleanFp;
jmethodID g_rowdataSetByteFp;
jmethodID g_rowdataSetShortFp;
jmethodID g_rowdataSetIntFp;
jmethodID g_rowdataSetLongFp;
jmethodID g_rowdataSetFloatFp;
jmethodID g_rowdataSetDoubleFp;
jmethodID g_rowdataSetStringFp;
jmethodID g_rowdataSetTimestampFp;
jmethodID g_rowdataSetByteArrayFp;

#define JNI_SUCCESS          0
#define JNI_TDENGINE_ERROR  -1
#define JNI_CONNECTION_NULL -2
#define JNI_RESULT_SET_NULL -3
#define JNI_NUM_OF_FIELDS_0 -4
#define JNI_SQL_NULL        -5
#define JNI_FETCH_END       -6
#define JNI_OUT_OF_MEMORY   -7

void jniGetGlobalMethod(JNIEnv *env) {
  // make sure init function executed once
weixin_48148422's avatar
weixin_48148422 已提交
71
  switch (atomic_val_compare_exchange_32(&__init, 0, 1)) {
weixin_48148422's avatar
weixin_48148422 已提交
72 73 74 75 76
    case 0:
      break;
    case 1:
      do {
        taosMsleep(0);
weixin_48148422's avatar
weixin_48148422 已提交
77
      } while (atomic_load_32(&__init) == 1);
weixin_48148422's avatar
weixin_48148422 已提交
78 79
    case 2:
      return;
H
hzcheng 已提交
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
  }

  if (g_vm == NULL) {
    (*env)->GetJavaVM(env, &g_vm);
  }

  jclass arrayListClass = (*env)->FindClass(env, "java/util/ArrayList");
  g_arrayListClass = (*env)->NewGlobalRef(env, arrayListClass);
  g_arrayListConstructFp = (*env)->GetMethodID(env, g_arrayListClass, "<init>", "()V");
  g_arrayListAddFp = (*env)->GetMethodID(env, g_arrayListClass, "add", "(Ljava/lang/Object;)Z");
  (*env)->DeleteLocalRef(env, arrayListClass);

  jclass metadataClass = (*env)->FindClass(env, "com/taosdata/jdbc/ColumnMetaData");
  g_metadataClass = (*env)->NewGlobalRef(env, metadataClass);
  g_metadataConstructFp = (*env)->GetMethodID(env, g_metadataClass, "<init>", "()V");
  g_metadataColtypeField = (*env)->GetFieldID(env, g_metadataClass, "colType", "I");
  g_metadataColnameField = (*env)->GetFieldID(env, g_metadataClass, "colName", "Ljava/lang/String;");
  g_metadataColsizeField = (*env)->GetFieldID(env, g_metadataClass, "colSize", "I");
  g_metadataColindexField = (*env)->GetFieldID(env, g_metadataClass, "colIndex", "I");
  (*env)->DeleteLocalRef(env, metadataClass);

  jclass rowdataClass = (*env)->FindClass(env, "com/taosdata/jdbc/TSDBResultSetRowData");
  g_rowdataClass = (*env)->NewGlobalRef(env, rowdataClass);
  g_rowdataConstructor = (*env)->GetMethodID(env, g_rowdataClass, "<init>", "(I)V");
  g_rowdataClearFp = (*env)->GetMethodID(env, g_rowdataClass, "clear", "()V");
  g_rowdataSetBooleanFp = (*env)->GetMethodID(env, g_rowdataClass, "setBoolean", "(IZ)V");
  g_rowdataSetByteFp = (*env)->GetMethodID(env, g_rowdataClass, "setByte", "(IB)V");
  g_rowdataSetShortFp = (*env)->GetMethodID(env, g_rowdataClass, "setShort", "(IS)V");
  g_rowdataSetIntFp = (*env)->GetMethodID(env, g_rowdataClass, "setInt", "(II)V");
  g_rowdataSetLongFp = (*env)->GetMethodID(env, g_rowdataClass, "setLong", "(IJ)V");
  g_rowdataSetFloatFp = (*env)->GetMethodID(env, g_rowdataClass, "setFloat", "(IF)V");
  g_rowdataSetDoubleFp = (*env)->GetMethodID(env, g_rowdataClass, "setDouble", "(ID)V");
  g_rowdataSetStringFp = (*env)->GetMethodID(env, g_rowdataClass, "setString", "(ILjava/lang/String;)V");
  g_rowdataSetTimestampFp = (*env)->GetMethodID(env, g_rowdataClass, "setTimestamp", "(IJ)V");
  g_rowdataSetByteArrayFp = (*env)->GetMethodID(env, g_rowdataClass, "setByteArray", "(I[B)V");
  (*env)->DeleteLocalRef(env, rowdataClass);

weixin_48148422's avatar
weixin_48148422 已提交
117
  atomic_store_32(&__init, 2);
118
  jniDebug("native method register finished");
H
hzcheng 已提交
119 120
}

H
Haojun Liao 已提交
121 122
JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setAllocModeImp(JNIEnv *env, jobject jobj, jint jMode,
                                                                               jstring jPath, jboolean jAutoDump) {
123 124
  if (jPath != NULL) {
    const char *path = (*env)->GetStringUTFChars(env, jPath, NULL);
weixin_48148422's avatar
weixin_48148422 已提交
125
    taosSetAllocMode(jMode, path, !!jAutoDump);
126 127
    (*env)->ReleaseStringUTFChars(env, jPath, path);
  } else {
weixin_48148422's avatar
weixin_48148422 已提交
128
    taosSetAllocMode(jMode, NULL, !!jAutoDump);
129 130 131
  }
}

132
JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_dumpMemoryLeakImp(JNIEnv *env, jobject jobj) {
weixin_48148422's avatar
weixin_48148422 已提交
133
  taosDumpMemoryLeak();
134 135
}

H
hzcheng 已提交
136 137 138
JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_initImp(JNIEnv *env, jobject jobj, jstring jconfigDir) {
  if (jconfigDir != NULL) {
    const char *confDir = (*env)->GetStringUTFChars(env, jconfigDir, NULL);
B
Bomin Zhang 已提交
139 140
    if (confDir && strlen(confDir) != 0) {
      tstrncpy(configDir, confDir, TSDB_FILENAME_LEN);
H
hzcheng 已提交
141 142 143 144 145
    }
    (*env)->ReleaseStringUTFChars(env, jconfigDir, confDir);
  }

  jniGetGlobalMethod(env);
146
  jniDebug("jni initialized successfully, config directory: %s", configDir);
H
hzcheng 已提交
147 148 149 150 151
}

JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_setOptions(JNIEnv *env, jobject jobj, jint optionIndex,
                                                                          jstring optionValue) {
  if (optionValue == NULL) {
152
    jniDebug("option index:%d value is null", optionIndex);
H
hzcheng 已提交
153 154 155 156 157 158 159 160 161
    return 0;
  }

  int res = 0;

  if (optionIndex == TSDB_OPTION_LOCALE) {
    const char *locale = (*env)->GetStringUTFChars(env, optionValue, NULL);
    if (locale && strlen(locale) != 0) {
      res = taos_options(TSDB_OPTION_LOCALE, locale);
162
      jniDebug("set locale to %s, result:%d", locale, res);
H
hzcheng 已提交
163
    } else {
164
      jniDebug("input locale is empty");
H
hzcheng 已提交
165 166 167 168 169 170
    }
    (*env)->ReleaseStringUTFChars(env, optionValue, locale);
  } else if (optionIndex == TSDB_OPTION_CHARSET) {
    const char *charset = (*env)->GetStringUTFChars(env, optionValue, NULL);
    if (charset && strlen(charset) != 0) {
      res = taos_options(TSDB_OPTION_CHARSET, charset);
171
      jniDebug("set character encoding to %s, result:%d", charset, res);
H
hzcheng 已提交
172
    } else {
173
      jniDebug("input character encoding is empty");
H
hzcheng 已提交
174 175 176
    }
    (*env)->ReleaseStringUTFChars(env, optionValue, charset);
  } else if (optionIndex == TSDB_OPTION_TIMEZONE) {
H
Haojun Liao 已提交
177 178 179
    const char *tz1 = (*env)->GetStringUTFChars(env, optionValue, NULL);
    if (tz1 && strlen(tz1) != 0) {
      res = taos_options(TSDB_OPTION_TIMEZONE, tz1);
180
      jniDebug("set timezone to %s, result:%d", tz1, res);
H
hzcheng 已提交
181
    } else {
182
      jniDebug("input timezone is empty");
H
hzcheng 已提交
183
    }
H
Haojun Liao 已提交
184
    (*env)->ReleaseStringUTFChars(env, optionValue, tz1);
H
hzcheng 已提交
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
  } else {
    jniError("option index:%d is not found", optionIndex);
  }

  return res;
}

JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_connectImp(JNIEnv *env, jobject jobj, jstring jhost,
                                                                           jint jport, jstring jdbName, jstring juser,
                                                                           jstring jpass) {
  jlong       ret = 0;
  const char *host = NULL;
  const char *dbname = NULL;
  const char *user = NULL;
  const char *pass = NULL;

  if (jhost != NULL) {
    host = (*env)->GetStringUTFChars(env, jhost, NULL);
  }
  if (jdbName != NULL) {
    dbname = (*env)->GetStringUTFChars(env, jdbName, NULL);
  }
  if (juser != NULL) {
    user = (*env)->GetStringUTFChars(env, juser, NULL);
  }
  if (jpass != NULL) {
    pass = (*env)->GetStringUTFChars(env, jpass, NULL);
  }

  if (user == NULL) {
215
    jniDebug("jobj:%p, user is null, use default user %s", jobj, TSDB_DEFAULT_USER);
H
hzcheng 已提交
216 217
  }
  if (pass == NULL) {
218
    jniDebug("jobj:%p, pass is null, use default password", jobj);
H
hzcheng 已提交
219 220 221
  }

  /*
H
Haojun Liao 已提交
222 223 224
   * set numOfThreadsPerCore = 0
   * means only one thread for client side scheduler
   */
H
hzcheng 已提交
225 226
  tsNumOfThreadsPerCore = 0.0;

S
Shengliang Guan 已提交
227
  ret = (jlong)taos_connect((char *)host, (char *)user, (char *)pass, (char *)dbname, (uint16_t)jport);
H
hzcheng 已提交
228
  if (ret == 0) {
S
slguan 已提交
229
    jniError("jobj:%p, conn:%p, connect to database failed, host=%s, user=%s, dbname=%s, port=%d", jobj, (void *)ret,
H
hzcheng 已提交
230 231
             (char *)host, (char *)user, (char *)dbname, jport);
  } else {
232
    jniDebug("jobj:%p, conn:%p, connect to database succeed, host=%s, user=%s, dbname=%s, port=%d", jobj, (void *)ret,
H
hzcheng 已提交
233 234 235 236 237
             (char *)host, (char *)user, (char *)dbname, jport);
  }

  if (host != NULL) (*env)->ReleaseStringUTFChars(env, jhost, host);
  if (dbname != NULL) (*env)->ReleaseStringUTFChars(env, jdbName, dbname);
S
Shengliang Guan 已提交
238 239
  if (user != NULL) (*env)->ReleaseStringUTFChars(env, juser, user);
  if (pass != NULL) (*env)->ReleaseStringUTFChars(env, jpass, pass);
H
hzcheng 已提交
240 241 242 243

  return ret;
}

H
Haojun Liao 已提交
244
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_executeQueryImp(JNIEnv *env, jobject jobj,
H
Haojun Liao 已提交
245
                                                                                jbyteArray jsql, jlong con) {
H
hzcheng 已提交
246 247
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
S
slguan 已提交
248
    jniError("jobj:%p, connection is already closed", jobj);
H
hzcheng 已提交
249 250 251 252
    return JNI_CONNECTION_NULL;
  }

  if (jsql == NULL) {
S
slguan 已提交
253
    jniError("jobj:%p, conn:%p, sql is null", jobj, tscon);
H
hzcheng 已提交
254 255 256 257 258 259 260
    return JNI_SQL_NULL;
  }

  jsize len = (*env)->GetArrayLength(env, jsql);

  char *dst = (char *)calloc(1, sizeof(char) * (len + 1));
  if (dst == NULL) {
S
slguan 已提交
261
    jniError("jobj:%p, conn:%p, can not alloc memory", jobj, tscon);
H
hzcheng 已提交
262 263 264 265 266
    return JNI_OUT_OF_MEMORY;
  }

  (*env)->GetByteArrayRegion(env, jsql, 0, len, (jbyte *)dst);
  if ((*env)->ExceptionCheck(env)) {
H
Haojun Liao 已提交
267
    // todo handle error
H
hzcheng 已提交
268 269
  }

270
  jniDebug("jobj:%p, conn:%p, sql:%s", jobj, tscon, dst);
S
slguan 已提交
271

H
Haojun Liao 已提交
272
  SSqlObj *pSql = taos_query(tscon, dst);
H
Haojun Liao 已提交
273
  int32_t  code = taos_errno(pSql);
H
hzcheng 已提交
274

H
Haojun Liao 已提交
275 276
  if (code != TSDB_CODE_SUCCESS) {
    jniError("jobj:%p, conn:%p, code:%s, msg:%s", jobj, tscon, tstrerror(code), taos_errstr(pSql));
H
hzcheng 已提交
277
  } else {
H
Haojun Liao 已提交
278
    int32_t affectRows = 0;
H
hzcheng 已提交
279
    if (pSql->cmd.command == TSDB_SQL_INSERT) {
H
Haojun Liao 已提交
280
      affectRows = taos_affected_rows(pSql);
281
      jniDebug("jobj:%p, conn:%p, code:%s, affect rows:%d", jobj, tscon, tstrerror(code), affectRows);
H
hzcheng 已提交
282
    } else {
283
      jniDebug("jobj:%p, conn:%p, code:%s", jobj, tscon, tstrerror(code));
H
hzcheng 已提交
284 285
    }
  }
H
Haojun Liao 已提交
286

H
Haojun Liao 已提交
287
  free(dst);
H
Haojun Liao 已提交
288
  return (jlong)pSql;
H
hzcheng 已提交
289 290
}

S
Shuaiqiang Chang 已提交
291
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrCodeImp(JNIEnv *env, jobject jobj, jlong con, jlong tres) {
H
hzcheng 已提交
292 293 294
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
295
    return (jint)TSDB_CODE_TSC_INVALID_CONNECTION;
H
hzcheng 已提交
296 297
  }

S
Shuaiqiang Chang 已提交
298 299 300
  if ((void *)tres == NULL) {
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
    return JNI_RESULT_SET_NULL;
H
hzcheng 已提交
301 302
  }

S
Shuaiqiang Chang 已提交
303 304 305
  TAOS_RES *pSql = (TAOS_RES *)tres;

  return (jint)taos_errno(pSql);
H
hzcheng 已提交
306 307
}

H
Haojun Liao 已提交
308
JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getErrMsgImp(JNIEnv *env, jobject jobj, jlong tres) {
H
Haojun Liao 已提交
309
  TAOS_RES *pSql = (TAOS_RES *)tres;
H
Haojun Liao 已提交
310
  return (*env)->NewStringUTF(env, (const char *)taos_errstr(pSql));
H
hzcheng 已提交
311 312
}

H
Haojun Liao 已提交
313 314
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getResultSetImp(JNIEnv *env, jobject jobj, jlong con,
                                                                                jlong tres) {
H
hzcheng 已提交
315 316 317 318 319 320
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

H
Haojun Liao 已提交
321
  if ((void *)tres == NULL) {
H
Haojun Liao 已提交
322 323 324
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
    return JNI_RESULT_SET_NULL;
  }
H
Haojun Liao 已提交
325 326 327

  SSqlObj *pSql = (TAOS_RES *)tres;
  STscObj *pObj = pSql->pTscObj;
S
slguan 已提交
328

H
Haojun Liao 已提交
329
  if (tscIsUpdateQuery(pSql)) {
H
Haojun Liao 已提交
330
    jniDebug("jobj:%p, conn:%p, update query, no resultset, %p", jobj, pObj, (void *)tres);
S
slguan 已提交
331
  } else {
332
    jniDebug("jobj:%p, conn:%p, get resultset, %p", jobj, pObj, (void *)tres);
H
hzcheng 已提交
333
  }
H
Haojun Liao 已提交
334 335

  return tres;
H
hzcheng 已提交
336 337
}

H
Haojun Liao 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_isUpdateQueryImp(JNIEnv *env, jobject jobj, jlong con,
                                                                                jlong tres) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

  if ((void *)tres == NULL) {
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
    return JNI_RESULT_SET_NULL;
  }

  SSqlObj *pSql = (TAOS_RES *)tres;

  return (tscIsUpdateQuery(pSql)? 1:0);
}

H
hzcheng 已提交
356 357 358 359 360 361 362 363 364
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_freeResultSetImp(JNIEnv *env, jobject jobj, jlong con,
                                                                                jlong res) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

  if ((void *)res == NULL) {
S
slguan 已提交
365
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
366 367 368 369
    return JNI_RESULT_SET_NULL;
  }

  taos_free_result((void *)res);
370
  jniDebug("jobj:%p, conn:%p, free resultset:%p", jobj, tscon, (void *)res);
H
hzcheng 已提交
371 372 373
  return JNI_SUCCESS;
}

H
Haojun Liao 已提交
374 375
JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getAffectedRowsImp(JNIEnv *env, jobject jobj, jlong con,
                                                                                  jlong res) {
H
hzcheng 已提交
376 377 378 379 380 381
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

H
Haojun Liao 已提交
382 383 384 385
  if ((void *)res == NULL) {
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
    return JNI_RESULT_SET_NULL;
  }
H
hzcheng 已提交
386

H
Haojun Liao 已提交
387
  jint ret = taos_affected_rows((SSqlObj *)res);
388
  jniDebug("jobj:%p, conn:%p, sql:%p, res: %p, affect rows:%d", jobj, tscon, (void *)con, (void *)res, ret);
H
hzcheng 已提交
389 390 391 392 393 394 395 396 397 398 399 400 401 402 403

  return ret;
}

JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getSchemaMetaDataImp(JNIEnv *env, jobject jobj,
                                                                                    jlong con, jlong res,
                                                                                    jobject arrayListObj) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

  TAOS_RES *result = (TAOS_RES *)res;
  if (result == NULL) {
S
slguan 已提交
404
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
405 406 407 408 409 410 411 412 413
    return JNI_RESULT_SET_NULL;
  }

  TAOS_FIELD *fields = taos_fetch_fields(result);
  int         num_fields = taos_num_fields(result);

  // jobject arrayListObj = (*env)->NewObject(env, g_arrayListClass, g_arrayListConstructFp, "");

  if (num_fields == 0) {
S
Shuaiqiang Chang 已提交
414
    jniError("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void *)res, num_fields);
H
hzcheng 已提交
415 416
    return JNI_NUM_OF_FIELDS_0;
  } else {
417
    jniDebug("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void *)res, num_fields);
H
hzcheng 已提交
418 419 420 421 422 423 424 425 426 427 428 429 430 431
    for (int i = 0; i < num_fields; ++i) {
      jobject metadataObj = (*env)->NewObject(env, g_metadataClass, g_metadataConstructFp);
      (*env)->SetIntField(env, metadataObj, g_metadataColtypeField, fields[i].type);
      (*env)->SetIntField(env, metadataObj, g_metadataColsizeField, fields[i].bytes);
      (*env)->SetIntField(env, metadataObj, g_metadataColindexField, i);
      jstring metadataObjColname = (*env)->NewStringUTF(env, fields[i].name);
      (*env)->SetObjectField(env, metadataObj, g_metadataColnameField, metadataObjColname);
      (*env)->CallBooleanMethod(env, arrayListObj, g_arrayListAddFp, metadataObj);
    }
  }

  return JNI_SUCCESS;
}

S
slguan 已提交
432 433 434 435 436 437 438 439
/**
 *
 * @param env      vm
 * @param nchar    true multibytes data
 * @param maxBytes the maximum allowable field length
 * @return
 */
jstring jniFromNCharToByteArray(JNIEnv *env, char *nchar, int32_t maxBytes) {
440 441
  jbyteArray bytes = (*env)->NewByteArray(env, maxBytes);
  (*env)->SetByteArrayRegion(env, bytes, 0, maxBytes, (jbyte *)nchar);
H
hzcheng 已提交
442 443 444 445 446 447 448 449 450 451 452 453 454
  return bytes;
}

JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_fetchRowImp(JNIEnv *env, jobject jobj, jlong con,
                                                                           jlong res, jobject rowobj) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

  TAOS_RES *result = (TAOS_RES *)res;
  if (result == NULL) {
S
slguan 已提交
455
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
456 457 458 459 460 461 462
    return JNI_RESULT_SET_NULL;
  }

  TAOS_FIELD *fields = taos_fetch_fields(result);
  int         num_fields = taos_num_fields(result);

  if (num_fields == 0) {
B
Bomin Zhang 已提交
463
    jniError("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void*)res, num_fields);
H
hzcheng 已提交
464 465 466 467 468
    return JNI_NUM_OF_FIELDS_0;
  }

  TAOS_ROW row = taos_fetch_row(result);
  if (row == NULL) {
S
Shuaiqiang Chang 已提交
469
    int tserrno = taos_errno(result);
470
    if (tserrno == 0) {
471
      jniDebug("jobj:%p, conn:%p, resultset:%p, fields size is %d, fetch row to the end", jobj, tscon, (void*)res, num_fields);
472 473
      return JNI_FETCH_END;
    } else {
474
      jniDebug("jobj:%p, conn:%p, interruptted query", jobj, tscon);
F
fangpanpan 已提交
475
      return JNI_RESULT_SET_NULL;
476
    }
H
hzcheng 已提交
477 478
  }

479 480
  int32_t* length = taos_fetch_lengths(result);

S
slguan 已提交
481 482
  char tmp[TSDB_MAX_BYTES_PER_ROW] = {0};

H
hzcheng 已提交
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503
  for (int i = 0; i < num_fields; i++) {
    if (row[i] == NULL) {
      continue;
    }

    switch (fields[i].type) {
      case TSDB_DATA_TYPE_BOOL:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetBooleanFp, i, (jboolean)(*((char *)row[i]) == 1));
        break;
      case TSDB_DATA_TYPE_TINYINT:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteFp, i, (jbyte) * ((char *)row[i]));
        break;
      case TSDB_DATA_TYPE_SMALLINT:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetShortFp, i, (jshort) * ((short *)row[i]));
        break;
      case TSDB_DATA_TYPE_INT:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetIntFp, i, (jint) * (int *)row[i]);
        break;
      case TSDB_DATA_TYPE_BIGINT:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetLongFp, i, (jlong) * ((int64_t *)row[i]));
        break;
L
lihui 已提交
504 505 506 507
      case TSDB_DATA_TYPE_FLOAT: {
        float fv = 0;
        fv = GET_FLOAT_VAL(row[i]);
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetFloatFp, i, (jfloat)fv);
H
Haojun Liao 已提交
508
      } break;
L
lihui 已提交
509 510 511 512
      case TSDB_DATA_TYPE_DOUBLE: {
        double dv = 0;
        dv = GET_DOUBLE_VAL(row[i]);
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetDoubleFp, i, (jdouble)dv);
H
Haojun Liao 已提交
513
      } break;
H
hjxilinx 已提交
514
      case TSDB_DATA_TYPE_BINARY: {
515
        memcpy(tmp, row[i], length[i]);  // handle the case that terminated does not exist
S
slguan 已提交
516 517
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetStringFp, i, (*env)->NewStringUTF(env, tmp));

518
        memset(tmp, 0, length[i]);
H
hzcheng 已提交
519
        break;
S
slguan 已提交
520
      }
H
hjxilinx 已提交
521
      case TSDB_DATA_TYPE_NCHAR: {
S
slguan 已提交
522
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteArrayFp, i,
523
                               jniFromNCharToByteArray(env, (char *)row[i], length[i]));
H
hzcheng 已提交
524
        break;
S
slguan 已提交
525
      }
H
hzcheng 已提交
526 527 528 529 530 531 532 533 534 535 536 537 538 539 540
      case TSDB_DATA_TYPE_TIMESTAMP:
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetTimestampFp, i, (jlong) * ((int64_t *)row[i]));
        break;
      default:
        break;
    }
  }

  return JNI_SUCCESS;
}

JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_closeConnectionImp(JNIEnv *env, jobject jobj,
                                                                                  jlong con) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
S
slguan 已提交
541
    jniError("jobj:%p, connection is already closed", jobj);
H
hzcheng 已提交
542 543
    return JNI_CONNECTION_NULL;
  } else {
544
    jniDebug("jobj:%p, conn:%p, close connection success", jobj, tscon);
H
hzcheng 已提交
545 546 547 548 549
    taos_close(tscon);
    return JNI_SUCCESS;
  }
}

weixin_48148422's avatar
weixin_48148422 已提交
550 551 552 553 554 555
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_subscribeImp(JNIEnv *env, jobject jobj, jlong con,
                                                                             jboolean restart, jstring jtopic, jstring jsql, jint jinterval) {
  jlong sub = 0;
  TAOS *taos = (TAOS *)con;
  char *topic = NULL;
  char *sql = NULL;
H
hzcheng 已提交
556 557

  jniGetGlobalMethod(env);
558
  jniDebug("jobj:%p, in TSDBJNIConnector_subscribeImp", jobj);
H
hzcheng 已提交
559

weixin_48148422's avatar
weixin_48148422 已提交
560 561
  if (jtopic != NULL) {
    topic = (char *)(*env)->GetStringUTFChars(env, jtopic, NULL);
H
hzcheng 已提交
562
  }
weixin_48148422's avatar
weixin_48148422 已提交
563 564
  if (jsql != NULL) {
    sql = (char *)(*env)->GetStringUTFChars(env, jsql, NULL);
H
hzcheng 已提交
565 566
  }

B
Bomin Zhang 已提交
567
  if (topic == NULL || sql == NULL) {
568
    jniDebug("jobj:%p, invalid argument: topic or sql is NULL", jobj);
B
Bomin Zhang 已提交
569 570 571
    return sub;
  }

weixin_48148422's avatar
weixin_48148422 已提交
572
  TAOS_SUB *tsub = taos_subscribe(taos, (int)restart, topic, sql, NULL, NULL, jinterval);
H
hzcheng 已提交
573 574 575
  sub = (jlong)tsub;

  if (sub == 0) {
576
    jniDebug("jobj:%p, failed to subscribe: topic:%s", jobj, topic);
H
hzcheng 已提交
577
  } else {
578
    jniDebug("jobj:%p, successfully subscribe: topic: %s", jobj, topic);
H
hzcheng 已提交
579 580
  }

B
Bomin Zhang 已提交
581 582
  (*env)->ReleaseStringUTFChars(env, jtopic, topic);
  (*env)->ReleaseStringUTFChars(env, jsql, sql);
H
hzcheng 已提交
583 584 585 586

  return sub;
}

587
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_consumeImp(JNIEnv *env, jobject jobj, jlong sub) {
588
  jniDebug("jobj:%p, in TSDBJNIConnector_consumeImp, sub:%lld", jobj, sub);
weixin_48148422's avatar
weixin_48148422 已提交
589 590 591 592
  jniGetGlobalMethod(env);

  TAOS_SUB *tsub = (TAOS_SUB *)sub;

S
Shuaiqiang Chang 已提交
593
  TAOS_RES *res = taos_consume(tsub);
weixin_48148422's avatar
weixin_48148422 已提交
594

S
Shuaiqiang Chang 已提交
595 596
  if (res == NULL) {
    jniError("jobj:%p, tsub:%p, taos_consume returns NULL", jobj, tsub);
S
Shuaiqiang Chang 已提交
597
    return 0l;
weixin_48148422's avatar
weixin_48148422 已提交
598 599
  }

600
  return (jlong)res;
weixin_48148422's avatar
weixin_48148422 已提交
601 602
}

H
Haojun Liao 已提交
603 604
JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_unsubscribeImp(JNIEnv *env, jobject jobj, jlong sub,
                                                                              jboolean keepProgress) {
H
hzcheng 已提交
605
  TAOS_SUB *tsub = (TAOS_SUB *)sub;
weixin_48148422's avatar
weixin_48148422 已提交
606
  taos_unsubscribe(tsub, keepProgress);
H
hzcheng 已提交
607 608 609 610 611 612 613 614 615 616 617
}

JNIEXPORT jint JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_validateCreateTableSqlImp(JNIEnv *env, jobject jobj,
                                                                                         jlong con, jbyteArray jsql) {
  TAOS *tscon = (TAOS *)con;
  if (tscon == NULL) {
    jniError("jobj:%p, connection is closed", jobj);
    return JNI_CONNECTION_NULL;
  }

  if (jsql == NULL) {
S
slguan 已提交
618
    jniError("jobj:%p, conn:%p, sql is null", jobj, tscon);
H
hzcheng 已提交
619 620 621 622 623 624 625 626
    return JNI_SQL_NULL;
  }

  jsize len = (*env)->GetArrayLength(env, jsql);

  char *dst = (char *)calloc(1, sizeof(char) * (len + 1));
  (*env)->GetByteArrayRegion(env, jsql, 0, len, (jbyte *)dst);
  if ((*env)->ExceptionCheck(env)) {
H
Haojun Liao 已提交
627
    // todo handle error
H
hzcheng 已提交
628 629 630
  }

  int code = taos_validate_sql(tscon, dst);
631
  jniDebug("jobj:%p, conn:%p, code is %d", jobj, tscon, code);
H
hzcheng 已提交
632

S
slguan 已提交
633
  free(dst);
H
hzcheng 已提交
634 635 636 637 638
  return code;
}

JNIEXPORT jstring JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_getTsCharset(JNIEnv *env, jobject jobj) {
  return (*env)->NewStringUTF(env, (const char *)tsCharset);
L
lihui 已提交
639
}