TSDBJNIConnector.c 22.7 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)) {
S
Shuaiqiang Chang 已提交
330
    // taos_free_result(pSql);  // free result here
331
    jniDebug("jobj:%p, conn:%p, no resultset, %p", jobj, pObj, (void *)tres);
H
Haojun Liao 已提交
332
    return 0;
S
slguan 已提交
333
  } else {
334
    jniDebug("jobj:%p, conn:%p, get resultset, %p", jobj, pObj, (void *)tres);
H
Haojun Liao 已提交
335
    return tres;
H
hzcheng 已提交
336 337 338 339 340 341 342 343 344 345 346 347
  }
}

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 已提交
348
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
349 350 351 352
    return JNI_RESULT_SET_NULL;
  }

  taos_free_result((void *)res);
353
  jniDebug("jobj:%p, conn:%p, free resultset:%p", jobj, tscon, (void *)res);
H
hzcheng 已提交
354 355 356
  return JNI_SUCCESS;
}

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

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

H
Haojun Liao 已提交
370
  jint ret = taos_affected_rows((SSqlObj *)res);
371
  jniDebug("jobj:%p, conn:%p, sql:%p, res: %p, affect rows:%d", jobj, tscon, (void *)con, (void *)res, ret);
H
hzcheng 已提交
372 373 374 375 376 377 378 379 380 381 382 383 384 385 386

  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 已提交
387
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
388 389 390 391 392 393 394 395 396
    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 已提交
397
    jniError("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void *)res, num_fields);
H
hzcheng 已提交
398 399
    return JNI_NUM_OF_FIELDS_0;
  } else {
400
    jniDebug("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void *)res, num_fields);
H
hzcheng 已提交
401 402 403 404 405 406 407 408 409 410 411 412 413 414
    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 已提交
415 416 417 418 419 420 421 422
/**
 *
 * @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) {
H
Haojun Liao 已提交
423
  int len = (int)strlen(nchar);
S
slguan 已提交
424 425 426 427
  if (len > maxBytes) {  // no terminated symbol exists '\0'
    len = maxBytes;
  }

H
hzcheng 已提交
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
  jbyteArray bytes = (*env)->NewByteArray(env, len);
  (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte *)nchar);
  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 已提交
443
    jniError("jobj:%p, conn:%p, resultset is null", jobj, tscon);
H
hzcheng 已提交
444 445 446 447 448 449 450
    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 已提交
451
    jniError("jobj:%p, conn:%p, resultset:%p, fields size is %d", jobj, tscon, (void*)res, num_fields);
H
hzcheng 已提交
452 453 454 455 456
    return JNI_NUM_OF_FIELDS_0;
  }

  TAOS_ROW row = taos_fetch_row(result);
  if (row == NULL) {
S
Shuaiqiang Chang 已提交
457
    int tserrno = taos_errno(result);
458
    if (tserrno == 0) {
459
      jniDebug("jobj:%p, conn:%p, resultset:%p, fields size is %d, fetch row to the end", jobj, tscon, (void*)res, num_fields);
460 461
      return JNI_FETCH_END;
    } else {
462
      jniDebug("jobj:%p, conn:%p, interruptted query", jobj, tscon);
F
fangpanpan 已提交
463
      return JNI_RESULT_SET_NULL;
464
    }
H
hzcheng 已提交
465 466
  }

S
slguan 已提交
467 468
  char tmp[TSDB_MAX_BYTES_PER_ROW] = {0};

H
hzcheng 已提交
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
  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 已提交
490 491 492 493
      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 已提交
494
      } break;
L
lihui 已提交
495 496 497 498
      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 已提交
499
      } break;
H
hjxilinx 已提交
500
      case TSDB_DATA_TYPE_BINARY: {
H
Haojun Liao 已提交
501
        strncpy(tmp, row[i], (size_t)fields[i].bytes);  // handle the case that terminated does not exist
S
slguan 已提交
502 503
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetStringFp, i, (*env)->NewStringUTF(env, tmp));

H
Haojun Liao 已提交
504
        memset(tmp, 0, (size_t)fields[i].bytes);
H
hzcheng 已提交
505
        break;
S
slguan 已提交
506
      }
H
hjxilinx 已提交
507
      case TSDB_DATA_TYPE_NCHAR: {
S
slguan 已提交
508
        (*env)->CallVoidMethod(env, rowobj, g_rowdataSetByteArrayFp, i,
H
Haojun Liao 已提交
509
                               jniFromNCharToByteArray(env, (char *)row[i], fields[i].bytes));
H
hzcheng 已提交
510
        break;
S
slguan 已提交
511
      }
H
hzcheng 已提交
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526
      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 已提交
527
    jniError("jobj:%p, connection is already closed", jobj);
H
hzcheng 已提交
528 529
    return JNI_CONNECTION_NULL;
  } else {
530
    jniDebug("jobj:%p, conn:%p, close connection success", jobj, tscon);
H
hzcheng 已提交
531 532 533 534 535
    taos_close(tscon);
    return JNI_SUCCESS;
  }
}

weixin_48148422's avatar
weixin_48148422 已提交
536 537 538 539 540 541
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 已提交
542 543

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

weixin_48148422's avatar
weixin_48148422 已提交
546 547
  if (jtopic != NULL) {
    topic = (char *)(*env)->GetStringUTFChars(env, jtopic, NULL);
H
hzcheng 已提交
548
  }
weixin_48148422's avatar
weixin_48148422 已提交
549 550
  if (jsql != NULL) {
    sql = (char *)(*env)->GetStringUTFChars(env, jsql, NULL);
H
hzcheng 已提交
551 552
  }

B
Bomin Zhang 已提交
553
  if (topic == NULL || sql == NULL) {
554
    jniDebug("jobj:%p, invalid argument: topic or sql is NULL", jobj);
B
Bomin Zhang 已提交
555 556 557
    return sub;
  }

weixin_48148422's avatar
weixin_48148422 已提交
558
  TAOS_SUB *tsub = taos_subscribe(taos, (int)restart, topic, sql, NULL, NULL, jinterval);
H
hzcheng 已提交
559 560 561
  sub = (jlong)tsub;

  if (sub == 0) {
562
    jniDebug("jobj:%p, failed to subscribe: topic:%s", jobj, topic);
H
hzcheng 已提交
563
  } else {
564
    jniDebug("jobj:%p, successfully subscribe: topic: %s", jobj, topic);
H
hzcheng 已提交
565 566
  }

B
Bomin Zhang 已提交
567 568
  (*env)->ReleaseStringUTFChars(env, jtopic, topic);
  (*env)->ReleaseStringUTFChars(env, jsql, sql);
H
hzcheng 已提交
569 570 571 572

  return sub;
}

573
JNIEXPORT jlong JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_consumeImp(JNIEnv *env, jobject jobj, jlong sub) {
574
  jniDebug("jobj:%p, in TSDBJNIConnector_consumeImp, sub:%lld", jobj, sub);
weixin_48148422's avatar
weixin_48148422 已提交
575 576 577 578
  jniGetGlobalMethod(env);

  TAOS_SUB *tsub = (TAOS_SUB *)sub;

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

S
Shuaiqiang Chang 已提交
581 582
  if (res == NULL) {
    jniError("jobj:%p, tsub:%p, taos_consume returns NULL", jobj, tsub);
S
Shuaiqiang Chang 已提交
583
    return 0l;
weixin_48148422's avatar
weixin_48148422 已提交
584 585
  }

S
Shuaiqiang Chang 已提交
586
  return (long)res;
weixin_48148422's avatar
weixin_48148422 已提交
587 588
}

H
Haojun Liao 已提交
589 590
JNIEXPORT void JNICALL Java_com_taosdata_jdbc_TSDBJNIConnector_unsubscribeImp(JNIEnv *env, jobject jobj, jlong sub,
                                                                              jboolean keepProgress) {
H
hzcheng 已提交
591
  TAOS_SUB *tsub = (TAOS_SUB *)sub;
weixin_48148422's avatar
weixin_48148422 已提交
592
  taos_unsubscribe(tsub, keepProgress);
H
hzcheng 已提交
593 594 595 596 597 598 599 600 601 602 603
}

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 已提交
604
    jniError("jobj:%p, conn:%p, sql is null", jobj, tscon);
H
hzcheng 已提交
605 606 607 608 609 610 611 612
    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 已提交
613
    // todo handle error
H
hzcheng 已提交
614 615 616
  }

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

S
slguan 已提交
619
  free(dst);
H
hzcheng 已提交
620 621 622 623 624
  return code;
}

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