Merge remote-tracking branch 'origin/feature/query' into feature/query
This commit is contained in:
commit
b2cbf6eb4a
|
@ -9,7 +9,7 @@ ELSEIF (TD_WINDOWS)
|
|||
ELSE ()
|
||||
SET(CMAKE_INSTALL_PREFIX C:/TDengine)
|
||||
ENDIF ()
|
||||
|
||||
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/go DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/nodejs DESTINATION connector)
|
||||
INSTALL(DIRECTORY ${TD_COMMUNITY_DIR}/src/connector/python DESTINATION connector)
|
||||
|
@ -20,12 +20,12 @@ ELSEIF (TD_WINDOWS)
|
|||
INSTALL(FILES ${TD_COMMUNITY_DIR}/src/inc/taoserror.h DESTINATION include)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.lib DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.exp DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.dll DESTINATION driver)
|
||||
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/taos.dll DESTINATION driver)
|
||||
|
||||
IF (TD_POWER)
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/power.exe DESTINATION .)
|
||||
ELSE ()
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/taos.exe DESTINATION .)
|
||||
ELSE ()
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/taos.exe DESTINATION .)
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/taosdemo.exe DESTINATION .)
|
||||
ENDIF ()
|
||||
|
||||
|
|
|
@ -312,7 +312,7 @@ function install_data() {
|
|||
}
|
||||
|
||||
function install_connector() {
|
||||
${csudo} cp -rf ${script_dir}/connector/* ${install_main_dir}/connector
|
||||
${csudo} cp -rf ${script_dir}/connector/ ${install_main_dir}/
|
||||
}
|
||||
|
||||
function install_examples() {
|
||||
|
|
|
@ -163,7 +163,7 @@ function install_log() {
|
|||
}
|
||||
|
||||
function install_connector() {
|
||||
${csudo} cp -rf ${script_dir}/connector/* ${install_main_dir}/connector
|
||||
${csudo} cp -rf ${script_dir}/connector/ ${install_main_dir}/
|
||||
}
|
||||
|
||||
function install_examples() {
|
||||
|
|
|
@ -20,6 +20,6 @@ ADD_SUBDIRECTORY(tsdb)
|
|||
ADD_SUBDIRECTORY(wal)
|
||||
ADD_SUBDIRECTORY(cq)
|
||||
ADD_SUBDIRECTORY(dnode)
|
||||
ADD_SUBDIRECTORY(connector/odbc)
|
||||
#ADD_SUBDIRECTORY(connector/odbc)
|
||||
ADD_SUBDIRECTORY(connector/jdbc)
|
||||
|
||||
|
|
|
@ -91,8 +91,8 @@ void taos_query_a(TAOS *taos, const char *sqlstr, __async_cb_func_t fp, void *pa
|
|||
int32_t sqlLen = (int32_t)strlen(sqlstr);
|
||||
if (sqlLen > tsMaxSQLStringLen) {
|
||||
tscError("sql string exceeds max length:%d", tsMaxSQLStringLen);
|
||||
terrno = TSDB_CODE_TSC_INVALID_SQL;
|
||||
tscQueueAsyncError(fp, param, TSDB_CODE_TSC_INVALID_SQL);
|
||||
terrno = TSDB_CODE_TSC_EXCEED_SQL_LIMIT;
|
||||
tscQueueAsyncError(fp, param, terrno);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,6 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
|
|||
|
||||
if (1) {
|
||||
// allow user bind param data with different type
|
||||
short size = 0;
|
||||
union {
|
||||
int8_t v1;
|
||||
int16_t v2;
|
||||
|
@ -600,7 +599,7 @@ static int doBindParam(char* data, SParamInfo* param, TAOS_BIND* bind) {
|
|||
if ((*bind->length) > (uintptr_t)param->bytes) {
|
||||
return TSDB_CODE_TSC_INVALID_VALUE;
|
||||
}
|
||||
size = (short)*bind->length;
|
||||
short size = (short)*bind->length;
|
||||
STR_WITH_SIZE_TO_VARSTR(data + param->offset, bind->buffer, size);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
} break;
|
||||
|
|
|
@ -321,7 +321,7 @@ TAOS_RES* taos_query_c(TAOS *taos, const char *sqlstr, uint32_t sqlLen, TAOS_RES
|
|||
|
||||
if (sqlLen > (uint32_t)tsMaxSQLStringLen) {
|
||||
tscError("sql string exceeds max length:%d", tsMaxSQLStringLen);
|
||||
terrno = TSDB_CODE_TSC_INVALID_SQL;
|
||||
terrno = TSDB_CODE_TSC_EXCEED_SQL_LIMIT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -864,18 +864,16 @@ int taos_validate_sql(TAOS *taos, const char *sql) {
|
|||
int32_t sqlLen = (int32_t)strlen(sql);
|
||||
if (sqlLen > tsMaxSQLStringLen) {
|
||||
tscError("%p sql too long", pSql);
|
||||
pRes->code = TSDB_CODE_TSC_INVALID_SQL;
|
||||
tfree(pSql);
|
||||
return pRes->code;
|
||||
return TSDB_CODE_TSC_EXCEED_SQL_LIMIT;
|
||||
}
|
||||
|
||||
pSql->sqlstr = realloc(pSql->sqlstr, sqlLen + 1);
|
||||
if (pSql->sqlstr == NULL) {
|
||||
pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||
tscError("%p failed to malloc sql string buffer", pSql);
|
||||
tscDebug("%p Valid SQL result:%d, %s pObj:%p", pSql, pRes->code, taos_errstr(pSql), pObj);
|
||||
tfree(pSql);
|
||||
return pRes->code;
|
||||
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
strtolower(pSql->sqlstr, sql);
|
||||
|
|
|
@ -594,7 +594,7 @@ void tscBuildVgroupTableInfo(SSqlObj* pSql, STableMetaInfo* pTableMetaInfo, SArr
|
|||
|
||||
if (taosArrayGetSize(result) > 0) {
|
||||
SVgroupTableInfo* prevGroup = taosArrayGet(result, taosArrayGetSize(result) - 1);
|
||||
tscDebug("%p vgId:%d, tables:%"PRId64, pSql, prevGroup->vgInfo.vgId, taosArrayGetSize(prevGroup->itemList));
|
||||
tscDebug("%p vgId:%d, tables:%"PRIzu, pSql, prevGroup->vgInfo.vgId, taosArrayGetSize(prevGroup->itemList));
|
||||
}
|
||||
|
||||
taosArrayPush(result, &info);
|
||||
|
@ -612,7 +612,7 @@ void tscBuildVgroupTableInfo(SSqlObj* pSql, STableMetaInfo* pTableMetaInfo, SArr
|
|||
|
||||
if (taosArrayGetSize(result) > 0) {
|
||||
SVgroupTableInfo* g = taosArrayGet(result, taosArrayGetSize(result) - 1);
|
||||
tscDebug("%p vgId:%d, tables:%"PRId64, pSql, g->vgInfo.vgId, taosArrayGetSize(g->itemList));
|
||||
tscDebug("%p vgId:%d, tables:%"PRIzu, pSql, g->vgInfo.vgId, taosArrayGetSize(g->itemList));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -753,7 +753,7 @@ static int32_t getIntersectionOfTableTuple(SQueryInfo* pQueryInfo, SSqlObj* pPar
|
|||
}
|
||||
#endif
|
||||
|
||||
tscDebug("%p tags match complete, result: %"PRId64", %"PRId64, pParentSql, t1, t2);
|
||||
tscDebug("%p tags match complete, result: %"PRIzu", %"PRIzu, pParentSql, t1, t2);
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit d598db167eb256fe67409b7bb3d0eb7fffc3ff8c
|
||||
Subproject commit ec77d9049a719dabfd1a7c1122a209e201861944
|
|
@ -5,24 +5,24 @@ import com.taosdata.jdbc.utils.TDNodes;
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
public class BaseTest {
|
||||
public abstract class BaseTest {
|
||||
|
||||
private static boolean testCluster = false;
|
||||
private static boolean testCluster = false;
|
||||
private static TDNodes nodes = new TDNodes();
|
||||
|
||||
|
||||
@BeforeClass
|
||||
public static void setupEnv() {
|
||||
try{
|
||||
try {
|
||||
if (nodes.getTDNode(1).getTaosdPid() != null) {
|
||||
System.out.println("Kill taosd before running JDBC test");
|
||||
nodes.getTDNode(1).setRunning(1);
|
||||
nodes.stop(1);
|
||||
}
|
||||
nodes.setTestCluster(testCluster);
|
||||
nodes.setTestCluster(testCluster);
|
||||
nodes.deploy(1);
|
||||
nodes.start(1);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
package com.taosdata.jdbc.cases;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.*;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class FailOverTest {
|
||||
|
||||
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
|
||||
|
||||
@Test
|
||||
public void testFailOver() throws ClassNotFoundException {
|
||||
Class.forName("com.taosdata.jdbc.TSDBDriver");
|
||||
final String url = "jdbc:TAOS://:/?user=root&password=taosdata";
|
||||
|
||||
long end = System.currentTimeMillis() + 1000 * 60 * 5;
|
||||
while (System.currentTimeMillis() < end) {
|
||||
try (Connection conn = DriverManager.getConnection(url)) {
|
||||
Statement stmt = conn.createStatement();
|
||||
ResultSet resultSet = stmt.executeQuery("select server_status()");
|
||||
resultSet.next();
|
||||
int status = resultSet.getInt("server_status()");
|
||||
System.out.println(">>>>>>>>>" + sdf.format(new Date()) + " status : " + status);
|
||||
stmt.close();
|
||||
TimeUnit.SECONDS.sleep(5);
|
||||
} catch (SQLException | InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,6 @@ PROJECT(TDengine)
|
|||
|
||||
IF (TD_LINUX_64)
|
||||
find_program(HAVE_ODBCINST NAMES odbcinst)
|
||||
|
||||
IF (HAVE_ODBCINST)
|
||||
include(CheckSymbolExists)
|
||||
# shall we revert CMAKE_REQUIRED_LIBRARIES and how?
|
||||
|
@ -14,20 +13,43 @@ IF (TD_LINUX_64)
|
|||
message(WARNING "unixodbc-dev is not installed yet, you may install it under ubuntu by typing: sudo apt install unixodbc-dev")
|
||||
else ()
|
||||
message(STATUS "unixodbc/unixodbc-dev are installed, and odbc connector will be built")
|
||||
AUX_SOURCE_DIRECTORY(src SRC)
|
||||
|
||||
# generate dynamic library (*.so)
|
||||
ADD_LIBRARY(todbc SHARED ${SRC})
|
||||
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
|
||||
TARGET_LINK_LIBRARIES(todbc taos)
|
||||
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/src/install.sh ${CMAKE_BINARY_DIR})")
|
||||
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
find_package(FLEX)
|
||||
if(NOT FLEX_FOUND)
|
||||
message(FATAL_ERROR "you need to install flex first")
|
||||
else ()
|
||||
if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0.0)
|
||||
message(WARNING "gcc 4.8.0 will complain too much about flex-generated code, we just bypass building ODBC driver in such case")
|
||||
else ()
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -Wconversion")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Wconversion")
|
||||
ADD_SUBDIRECTORY(src)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
endif ()
|
||||
endif()
|
||||
endif()
|
||||
ELSE ()
|
||||
message(WARNING "unixodbc is not installed yet, you may install it under ubuntu by typing: sudo apt install unixodbc")
|
||||
ENDIF ()
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_64)
|
||||
find_package(ODBC)
|
||||
if (NOT ODBC_FOUND)
|
||||
message(FATAL_ERROR "you need to install ODBC first")
|
||||
else ()
|
||||
message(STATUS "ODBC_INCLUDE_DIRS: ${ODBC_INCLUDE_DIRS}")
|
||||
message(STATUS "ODBC_LIBRARIES: ${ODBC_LIBRARIES}")
|
||||
message(STATUS "ODBC_CONFIG: ${ODBC_CONFIG}")
|
||||
endif ()
|
||||
find_package(FLEX)
|
||||
if(NOT FLEX_FOUND)
|
||||
message(WARNING "you need to install flex first\n"
|
||||
"you may go to: https://github.com/lexxmark/winflexbison\n"
|
||||
"or download from: https://github.com/lexxmark/winflexbison/releases")
|
||||
else ()
|
||||
ADD_SUBDIRECTORY(src)
|
||||
ADD_SUBDIRECTORY(tools)
|
||||
ADD_SUBDIRECTORY(tests)
|
||||
endif()
|
||||
ENDIF ()
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
|
||||
# ODBC Driver #
|
||||
|
||||
- **very initial implementation of ODBC driver for TAOS
|
||||
|
||||
- **currently partially supported ODBC functions are: `
|
||||
SQLAllocEnv
|
||||
SQLFreeEnv
|
||||
SQLAllocConnect
|
||||
SQLFreeConnect
|
||||
SQLConnect
|
||||
SQLDisconnect
|
||||
SQLAllocStmt
|
||||
SQLAllocHandle
|
||||
SQLFreeStmt
|
||||
SQLExecDirect
|
||||
SQLExecDirectW
|
||||
SQLNumResultCols
|
||||
SQLRowCount
|
||||
SQLColAttribute
|
||||
SQLGetData
|
||||
SQLFetch
|
||||
SQLPrepare
|
||||
SQLExecute
|
||||
SQLGetDiagField
|
||||
SQLGetDiagRec
|
||||
SQLBindParameter
|
||||
SQLDriverConnect
|
||||
SQLSetConnectAttr
|
||||
SQLDescribeCol
|
||||
SQLNumParams
|
||||
SQLSetStmtAttr
|
||||
ConfigDSN
|
||||
`
|
||||
|
||||
- **internationalized, you can specify different charset/code page for easy going. eg.: insert `utf-8.zh_cn` characters into database located in linux machine, while query them out in `gb2312/gb18030/...` code page in your chinese windows machine, or vice-versa. and much fun, insert `gb2312/gb18030/...` characters into database located in linux box from
|
||||
your japanese windows box, and query them out in your local chinese windows machine.
|
||||
|
||||
- **enable ODBC-aware software to communicate with TAOS.
|
||||
|
||||
- **enable any language with ODBC-bindings/ODBC-plugings to communicate with TAOS
|
||||
|
||||
- **still going on...
|
||||
|
||||
# Building and Testing
|
||||
**Note**: all `work` is done in TDengine's project directory
|
||||
|
||||
|
||||
# Building under Linux, use Ubuntu as example
|
||||
```
|
||||
sudo apt install unixodbc unixodbc-dev flex
|
||||
rm -rf debug && cmake -B debug && cmake --build debug && cmake --install debug && echo yes
|
||||
```
|
||||
# Building under Windows, use Windows 10 as example
|
||||
- install windows `flex` port. We use [https://github.com/lexxmark/winflexbison](url) at the moment. Please be noted to append `<path_to_win_flex.exe>` to your `PATH`.
|
||||
- install Microsoft Visual Studio, take VS2015 as example here
|
||||
- `"C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" amd64`
|
||||
- `rmdir /s /q debug`
|
||||
- `cmake -G "NMake Makefiles" -B debug`
|
||||
- `cmake --build debug`
|
||||
- `cmake --install debug`
|
||||
- open your `Command Prompt` with Administrator's priviledge
|
||||
- remove previously installed TAOS ODBC driver: run `C:\TDengine\todbcinst -u -f -n TAOS`
|
||||
- install TAOS ODBC driver that was just built: run `C:\TDengine\todbcinst -i -n TAOS -p C:\TDengine\driver`
|
||||
- add a new user dsn: run `odbcconf CONFIGDSN TAOS "DSN=TAOS_DSN|Server=<fqdn>:<port>`
|
||||
|
||||
# Test
|
||||
we highly suggest that you build both in linux(ubuntu) and windows(windows 10) platform, because currently TAOS only has it's server-side port on linux platform.
|
||||
**Note1**: content within <> shall be modified to match your environment
|
||||
**Note2**: `.stmts` source files are all encoded in `UTF-8`
|
||||
## start taosd in linux, suppose charset is `UTF-8` as default
|
||||
```
|
||||
taosd -c ./debug/test/cfg
|
||||
```
|
||||
## create data in linux
|
||||
```
|
||||
./debug/build/bin/tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts ./src/connector/odbc/tests/create_data.stmts
|
||||
--<or with driver connection string -->
|
||||
./debug/build/bin/tcodbc --dcs 'Driver=TAOS;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;client_enc=UTF-8' ./src/connector/odbc/tests/create_data.stmts
|
||||
```
|
||||
## query data in windows
|
||||
```
|
||||
.\debug\build\bin\tcodbc --dsn TAOS_DSN --uid <uid> --pwd <pwd> --sts .\src\connector\odbc\tests\query_data.stmts
|
||||
--<or with driver connection string -->
|
||||
.\debug\build\bin\tcodbc --dcs "Driver=TAOS;UID=<uid>;PWD=<pwd>;Server=<fqdn>:<port>;client_enc=UTF-8" .\src\connector\odbc\tests\query_data.stmts
|
||||
```
|
||||
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
|
||||
PROJECT(TDengine)
|
||||
|
||||
IF (TD_LINUX_64)
|
||||
FLEX_TARGET(todbcFlexScanner
|
||||
todbc_scanner.l
|
||||
${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c
|
||||
)
|
||||
set(todbc_flex_scanner_src
|
||||
${FLEX_todbcFlexScanner_OUTPUTS}
|
||||
)
|
||||
AUX_SOURCE_DIRECTORY(. SRC)
|
||||
|
||||
# generate dynamic library (*.so)
|
||||
ADD_LIBRARY(todbc SHARED ${SRC} ${todbc_flex_scanner_src})
|
||||
SET_TARGET_PROPERTIES(todbc PROPERTIES CLEAN_DIRECT_OUTPUT 1)
|
||||
SET_TARGET_PROPERTIES(todbc PROPERTIES VERSION ${TD_VER_NUMBER} SOVERSION 1)
|
||||
TARGET_LINK_LIBRARIES(todbc taos odbcinst)
|
||||
target_include_directories(todbc PUBLIC .)
|
||||
|
||||
install(CODE "execute_process(COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/install.sh ${CMAKE_BINARY_DIR})")
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_64)
|
||||
FLEX_TARGET(todbcFlexScanner
|
||||
todbc_scanner.l
|
||||
${CMAKE_CURRENT_BINARY_DIR}/todbc_scanner.c
|
||||
)
|
||||
set(todbc_flex_scanner_src
|
||||
${FLEX_todbcFlexScanner_OUTPUTS}
|
||||
)
|
||||
AUX_SOURCE_DIRECTORY(. SRC)
|
||||
|
||||
# generate dynamic library (*.dll)
|
||||
ADD_LIBRARY(todbc SHARED
|
||||
${SRC}
|
||||
${todbc_flex_scanner_src}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/todbc.rc
|
||||
todbc.def)
|
||||
TARGET_LINK_LIBRARIES(todbc taos_static odbccp32 legacy_stdio_definitions)
|
||||
target_include_directories(todbc PUBLIC .)
|
||||
target_compile_definitions(todbc PRIVATE "todbc_EXPORT")
|
||||
|
||||
CONFIGURE_FILE("todbc.rc.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/todbc.rc")
|
||||
SET_TARGET_PROPERTIES(todbc PROPERTIES LINK_FLAGS
|
||||
/DEF:todbc.def)
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /GL")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL")
|
||||
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.lib DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.exp DESTINATION driver)
|
||||
INSTALL(FILES ${LIBRARY_OUTPUT_PATH}/todbc.dll DESTINATION driver)
|
||||
ENDIF ()
|
|
@ -9,16 +9,18 @@ rm -f "${BLD_DIR}/template.dsn"
|
|||
|
||||
cat > "${BLD_DIR}/template.ini" <<EOF
|
||||
[TAOS]
|
||||
Description = taos odbc driver
|
||||
Driver = ${BLD_DIR}/build/lib/libtodbc.so
|
||||
Description=taos odbc driver
|
||||
Driver=${BLD_DIR}/build/lib/libtodbc.so
|
||||
EOF
|
||||
|
||||
cat > "${BLD_DIR}/template.dsn" <<EOF
|
||||
[TAOS_DSN]
|
||||
Description=Connection to TAOS
|
||||
Driver=TAOS
|
||||
Server=localhost:6030
|
||||
EOF
|
||||
|
||||
# better remove first ?
|
||||
sudo odbcinst -i -d -f "${BLD_DIR}/template.ini" &&
|
||||
odbcinst -i -s -f "${BLD_DIR}/template.dsn" &&
|
||||
echo "odbc install done"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,31 @@
|
|||
EXPORTS
|
||||
SQLAllocEnv
|
||||
SQLFreeEnv
|
||||
SQLAllocConnect
|
||||
SQLFreeConnect
|
||||
SQLConnect
|
||||
SQLDisconnect
|
||||
SQLAllocStmt
|
||||
SQLAllocHandle
|
||||
SQLFreeStmt
|
||||
SQLExecDirect
|
||||
SQLExecDirectW
|
||||
SQLNumResultCols
|
||||
SQLRowCount
|
||||
SQLColAttribute
|
||||
SQLGetData
|
||||
SQLFetch
|
||||
SQLPrepare
|
||||
SQLExecute
|
||||
SQLGetDiagField
|
||||
SQLGetDiagRec
|
||||
SQLBindParameter
|
||||
SQLDriverConnect
|
||||
SQLSetConnectAttr
|
||||
SQLDescribeCol
|
||||
SQLNumParams
|
||||
SQLSetStmtAttr
|
||||
ConfigDSN
|
||||
ConfigTranslator
|
||||
ConfigDriver
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
1 VERSIONINFO
|
||||
FILEVERSION ${TD_VER_NUMBER}
|
||||
PRODUCTVERSION ${TD_VER_NUMBER}
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x0L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "FileDescription", "ODBC Driver for TDengine"
|
||||
VALUE "FileVersion", "${TD_VER_NUMBER}"
|
||||
VALUE "InternalName", "todbc.dll(${TD_VER_CPUTYPE})"
|
||||
VALUE "LegalCopyright", "Copyright (C) 2020 TAOS Data"
|
||||
VALUE "OriginalFilename", ""
|
||||
VALUE "ProductName", "todbc.dll(${TD_VER_CPUTYPE})"
|
||||
VALUE "ProductVersion", "${TD_VER_NUMBER}"
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
|
@ -0,0 +1,5 @@
|
|||
INSTALLDRIVER "TAOS ODBC|Driver=todbc.dll|FileUsage=0|ConnectFunctions=YYN"
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,660 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#include "todbc_conv.h"
|
||||
|
||||
#include "todbc_log.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
const char* tsdb_conv_code_str(TSDB_CONV_CODE code) {
|
||||
switch (code) {
|
||||
case TSDB_CONV_OK: return "TSDB_CONV_OK";
|
||||
case TSDB_CONV_NOT_AVAIL: return "TSDB_CONV_NOT_AVAIL";
|
||||
case TSDB_CONV_OOM: return "TSDB_CONV_OOM";
|
||||
case TSDB_CONV_OOR: return "TSDB_CONV_OOR";
|
||||
case TSDB_CONV_TRUNC_FRACTION: return "TSDB_CONV_TRUNC_FRACTION";
|
||||
case TSDB_CONV_TRUNC: return "TSDB_CONV_TRUNC";
|
||||
case TSDB_CONV_CHAR_NOT_NUM: return "TSDB_CONV_CHAR_NOT_NUM";
|
||||
case TSDB_CONV_CHAR_NOT_TS: return "TSDB_CONV_CHAR_NOT_TS";
|
||||
case TSDB_CONV_NOT_VALID_TS: return "TSDB_CONV_NOT_VALID_TS";
|
||||
case TSDB_CONV_GENERAL: return "TSDB_CONV_GENERAL";
|
||||
case TSDB_CONV_SRC_TOO_LARGE: return "TSDB_CONV_SRC_TOO_LARGE";
|
||||
case TSDB_CONV_SRC_BAD_SEQ: return "TSDB_CONV_SRC_BAD_SEQ";
|
||||
case TSDB_CONV_SRC_INCOMPLETE: return "TSDB_CONV_SRC_INCOMPLETE";
|
||||
case TSDB_CONV_SRC_GENERAL: return "TSDB_CONV_SRC_GENERAL";
|
||||
case TSDB_CONV_BAD_CHAR: return "TSDB_CONV_BAD_CHAR";
|
||||
default: return "UNKNOWN";
|
||||
};
|
||||
}
|
||||
|
||||
// src: int
|
||||
TSDB_CONV_CODE tsdb_int64_to_bit(int64_t src, int8_t *dst) {
|
||||
*dst = (int8_t)src;
|
||||
if (src==0 || src==1) return TSDB_CONV_OK;
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_tinyint(int64_t src, int8_t *dst) {
|
||||
*dst = (int8_t)src;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_smallint(int64_t src, int16_t *dst) {
|
||||
*dst = (int16_t)src;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_int(int64_t src, int32_t *dst) {
|
||||
*dst = (int32_t)src;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_bigint(int64_t src, int64_t *dst) {
|
||||
*dst = src;
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_ts(int64_t src, int64_t *dst) {
|
||||
*dst = src;
|
||||
|
||||
time_t t = (time_t)(src / 1000);
|
||||
struct tm tm = {0};
|
||||
if (localtime_r(&t, &tm)) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_float(int64_t src, float *dst) {
|
||||
*dst = (float)src;
|
||||
|
||||
int64_t v = (int64_t)*dst;
|
||||
if (v==src) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_double(int64_t src, double *dst) {
|
||||
*dst = (double)src;
|
||||
|
||||
int64_t v = (int64_t)*dst;
|
||||
if (v==src) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_char(int64_t src, char *dst, size_t dlen) {
|
||||
int n = snprintf(dst, dlen, "%" PRId64 "", src);
|
||||
DASSERT(n>=0);
|
||||
|
||||
if (n<dlen) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
// src: double
|
||||
TSDB_CONV_CODE tsdb_double_to_bit(double src, int8_t *dst) {
|
||||
*dst = (int8_t)src;
|
||||
|
||||
if (src<0 || src>=2) return TSDB_CONV_OOR;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
|
||||
int64_t v = (int64_t)src;
|
||||
if (v == *dst) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_tinyint(double src, int8_t *dst) {
|
||||
*dst = (int8_t)src;
|
||||
|
||||
if (src<SCHAR_MIN || src>SCHAR_MAX) return TSDB_CONV_OOR;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
|
||||
int64_t v = (int64_t)src;
|
||||
if (v == *dst) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_smallint(double src, int16_t *dst) {
|
||||
*dst = (int16_t)src;
|
||||
|
||||
if (src<SHRT_MIN || src>SHRT_MAX) return TSDB_CONV_OOR;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
|
||||
int64_t v = (int64_t)src;
|
||||
if (v == *dst) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_int(double src, int32_t *dst) {
|
||||
*dst = (int32_t)src;
|
||||
|
||||
if (src<LONG_MIN || src>LONG_MAX) return TSDB_CONV_OOR;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
|
||||
int64_t v = (int64_t)src;
|
||||
if (v == *dst) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_bigint(double src, int64_t *dst) {
|
||||
*dst = (int64_t)src;
|
||||
|
||||
if (src<LLONG_MIN || src>LLONG_MAX) return TSDB_CONV_OOR;
|
||||
if (src == *dst) return TSDB_CONV_OK;
|
||||
|
||||
int64_t v = (int64_t)src;
|
||||
if (v == *dst) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_ts(double src, int64_t *dst) {
|
||||
TSDB_CONV_CODE code = tsdb_double_to_bigint(src, dst);
|
||||
|
||||
if (code==TSDB_CONV_OK || code==TSDB_CONV_TRUNC_FRACTION) {
|
||||
int64_t v = (int64_t)src;
|
||||
time_t t = (time_t)(v / 1000);
|
||||
struct tm tm = {0};
|
||||
if (localtime_r(&t, &tm)) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_char(double src, char *dst, size_t dlen) {
|
||||
int n = snprintf(dst, dlen, "%lg", src);
|
||||
DASSERT(n>=0);
|
||||
|
||||
if (n<dlen) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
// src: SQL_TIMESTAMP_STRUCT
|
||||
TSDB_CONV_CODE tsdb_timestamp_to_char(SQL_TIMESTAMP_STRUCT src, char *dst, size_t dlen) {
|
||||
int n = snprintf(dst, dlen, "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
||||
src.year, src.month, src.day,
|
||||
src.hour, src.minute, src.second,
|
||||
src.fraction / 1000000);
|
||||
DASSERT(n>=0);
|
||||
if (n<dlen) return TSDB_CONV_OK;
|
||||
|
||||
if (strlen(dst)>=19) return TSDB_CONV_TRUNC_FRACTION;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
// src: chars
|
||||
TSDB_CONV_CODE tsdb_chars_to_bit(const char *src, size_t smax, int8_t *dst) {
|
||||
if (strcmp(src, "0")==0) {
|
||||
*dst = 0;
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
if (strcmp(src, "1")==0) {
|
||||
*dst = 1;
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
double v;
|
||||
int bytes;
|
||||
int n = sscanf(src, "%lg%n", &v, &bytes);
|
||||
|
||||
if (n!=1) return TSDB_CONV_CHAR_NOT_NUM;
|
||||
if (bytes!=strlen(src)) return TSDB_CONV_CHAR_NOT_NUM;
|
||||
|
||||
if (v<0 || v>=2) return TSDB_CONV_OOR;
|
||||
|
||||
return TSDB_CONV_TRUNC_FRACTION;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_tinyint(const char *src, size_t smax, int8_t *dst) {
|
||||
int64_t v;
|
||||
TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v);
|
||||
if (code!=TSDB_CONV_OK) return code;
|
||||
|
||||
*dst = (int8_t)v;
|
||||
|
||||
if (v==*dst) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_smallint(const char *src, size_t smax, int16_t *dst) {
|
||||
int64_t v;
|
||||
TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v);
|
||||
if (code!=TSDB_CONV_OK) return code;
|
||||
|
||||
*dst = (int16_t)v;
|
||||
|
||||
if (v==*dst) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_int(const char *src, size_t smax, int32_t *dst) {
|
||||
int64_t v;
|
||||
TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v);
|
||||
if (code!=TSDB_CONV_OK) return code;
|
||||
|
||||
*dst = (int32_t)v;
|
||||
|
||||
if (v==*dst) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_bigint(const char *src, size_t smax, int64_t *dst) {
|
||||
int bytes;
|
||||
int n = sscanf(src, "%" PRId64 "%n", dst, &bytes);
|
||||
|
||||
if (n!=1) return TSDB_CONV_CHAR_NOT_NUM;
|
||||
if (bytes==strlen(src)) {
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
double v;
|
||||
n = sscanf(src, "%lg%n", &v, &bytes);
|
||||
if (n!=1) return TSDB_CONV_CHAR_NOT_NUM;
|
||||
if (bytes==strlen(src)) {
|
||||
return TSDB_CONV_TRUNC_FRACTION;
|
||||
}
|
||||
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_ts(const char *src, size_t smax, int64_t *dst) {
|
||||
int64_t v;
|
||||
TSDB_CONV_CODE code = tsdb_chars_to_bigint(src, smax, &v);
|
||||
if (code!=TSDB_CONV_OK) return code;
|
||||
|
||||
*dst = v;
|
||||
|
||||
if (v==*dst) {
|
||||
time_t t = (time_t)(v / 1000);
|
||||
struct tm tm = {0};
|
||||
if (localtime_r(&t, &tm)) return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
return TSDB_CONV_OOR;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_float(const char *src, size_t smax, float *dst) {
|
||||
int bytes;
|
||||
int n = sscanf(src, "%g%n", dst, &bytes);
|
||||
|
||||
if (n==1 && bytes==strlen(src)) {
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
return TSDB_CONV_CHAR_NOT_NUM;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst) {
|
||||
int bytes;
|
||||
int n = sscanf(src, "%lg%n", dst, &bytes);
|
||||
|
||||
if (n==1 && bytes==strlen(src)) {
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
return TSDB_CONV_CHAR_NOT_NUM;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst) {
|
||||
int64_t v = 0;
|
||||
// why cast to 'char*' ?
|
||||
int r = taosParseTime((char*)src, &v, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0);
|
||||
|
||||
if (r) {
|
||||
return TSDB_CONV_CHAR_NOT_TS;
|
||||
}
|
||||
|
||||
time_t t = v/1000;
|
||||
struct tm vtm = {0};
|
||||
localtime_r(&t, &vtm);
|
||||
dst->year = (SQLSMALLINT)(vtm.tm_year + 1900);
|
||||
dst->month = (SQLUSMALLINT)(vtm.tm_mon + 1);
|
||||
dst->day = (SQLUSMALLINT)(vtm.tm_mday);
|
||||
dst->hour = (SQLUSMALLINT)(vtm.tm_hour);
|
||||
dst->minute = (SQLUSMALLINT)(vtm.tm_min);
|
||||
dst->second = (SQLUSMALLINT)(vtm.tm_sec);
|
||||
dst->fraction = (SQLUINTEGER)(v%1000 * 1000000);
|
||||
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_timestamp_ts(const char *src, size_t smax, int64_t *dst) {
|
||||
// why cast to 'char*' ?
|
||||
int r = taosParseTime((char*)src, dst, (int32_t)smax, TSDB_TIME_PRECISION_MILLI, 0);
|
||||
|
||||
if (r) {
|
||||
return TSDB_CONV_CHAR_NOT_TS;
|
||||
}
|
||||
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax) {
|
||||
int n = snprintf(dst, dmax, "%s", src);
|
||||
DASSERT(n>=0);
|
||||
if (n<dmax) return TSDB_CONV_OK;
|
||||
|
||||
return TSDB_CONV_TRUNC;
|
||||
}
|
||||
|
||||
|
||||
char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes) {
|
||||
if (!buffer) return NULL;
|
||||
// align-by-size_of-size_t-bytes
|
||||
if (bytes==0) bytes = sizeof(size_t);
|
||||
bytes = (bytes + sizeof(size_t) - 1) / sizeof(size_t) * sizeof(size_t);
|
||||
|
||||
size_t next = buffer->next + bytes;
|
||||
if (next>sizeof(buffer->buf)) return NULL;
|
||||
|
||||
char *p = buffer->buf + buffer->next;
|
||||
buffer->next = next;
|
||||
return p;
|
||||
}
|
||||
|
||||
int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr) {
|
||||
if (!buffer) return 0;
|
||||
if (ptr>=buffer->buf && ptr<buffer->buf+buffer->next) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct tsdb_conv_s {
|
||||
iconv_t cnv;
|
||||
unsigned int direct:1;
|
||||
};
|
||||
|
||||
static tsdb_conv_t no_conversion = {0};
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
static void once_init(void) {
|
||||
no_conversion.cnv = (iconv_t)-1;
|
||||
no_conversion.direct = 1;
|
||||
}
|
||||
|
||||
tsdb_conv_t* tsdb_conv_direct() { // get a non-conversion-converter
|
||||
pthread_once(&once, once_init);
|
||||
return &no_conversion;
|
||||
}
|
||||
|
||||
tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc) {
|
||||
pthread_once(&once, once_init);
|
||||
tsdb_conv_t *cnv = (tsdb_conv_t*)calloc(1, sizeof(*cnv));
|
||||
if (!cnv) return NULL;
|
||||
if (strcmp(from_enc, to_enc)==0 && 0) {
|
||||
cnv->cnv = (iconv_t)-1;
|
||||
cnv->direct = 1;
|
||||
return cnv;
|
||||
}
|
||||
cnv->cnv = iconv_open(to_enc, from_enc);
|
||||
if (cnv->cnv == (iconv_t)-1) {
|
||||
free(cnv);
|
||||
return NULL;
|
||||
}
|
||||
cnv->direct = 0;
|
||||
return cnv;
|
||||
}
|
||||
|
||||
void tsdb_conv_close(tsdb_conv_t *cnv) {
|
||||
if (!cnv) return;
|
||||
if (cnv == &no_conversion) return;
|
||||
if (!cnv->direct) {
|
||||
if (cnv->cnv != (iconv_t)-1) {
|
||||
iconv_close(cnv->cnv);
|
||||
}
|
||||
}
|
||||
cnv->cnv = (iconv_t)-1;
|
||||
cnv->direct = 0;
|
||||
free(cnv);
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen) {
|
||||
if (!cnv) return TSDB_CONV_NOT_AVAIL;
|
||||
if (cnv->direct) {
|
||||
size_t n = (*slen > *dlen) ? *dlen : *slen;
|
||||
memcpy(dst, src, n);
|
||||
*slen -= n;
|
||||
*dlen -= n;
|
||||
if (*dlen) dst[n] = '\0';
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
if (!cnv->cnv) return TSDB_CONV_NOT_AVAIL;
|
||||
size_t r = iconv(cnv->cnv, (char**)&src, slen, &dst, dlen);
|
||||
if (r==(size_t)-1) return TSDB_CONV_BAD_CHAR;
|
||||
if (*slen) return TSDB_CONV_TRUNC;
|
||||
if (*dlen) *dst = '\0';
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen) {
|
||||
char utf8[64];
|
||||
int n = snprintf(utf8, sizeof(utf8), "%" PRId64 "", val);
|
||||
DASSERT(n>=0);
|
||||
DASSERT(n<sizeof(utf8));
|
||||
size_t len = (size_t)n;
|
||||
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
|
||||
*dlen = (size_t)n+1;
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_write_double(tsdb_conv_t *cnv, double val, char *dst, size_t *dlen) {
|
||||
char utf8[256];
|
||||
int n = snprintf(utf8, sizeof(utf8), "%g", val);
|
||||
DASSERT(n>=0);
|
||||
DASSERT(n<sizeof(utf8));
|
||||
size_t len = (size_t)n;
|
||||
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
|
||||
*dlen = (size_t)n+1;
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_write_timestamp(tsdb_conv_t *cnv, SQL_TIMESTAMP_STRUCT val, char *dst, size_t *dlen) {
|
||||
char utf8[256];
|
||||
int n = snprintf(utf8, sizeof(utf8), "%04d-%02d-%02d %02d:%02d:%02d.%03d",
|
||||
val.year, val.month, val.day,
|
||||
val.hour, val.minute, val.second,
|
||||
val.fraction / 1000000);
|
||||
DASSERT(n>=0);
|
||||
DASSERT(n<sizeof(utf8));
|
||||
size_t len = (size_t)n;
|
||||
TSDB_CONV_CODE code = tsdb_conv_write(cnv, utf8, &len, dst, dlen);
|
||||
*dlen = (size_t)n+1;
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_bit(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_bit(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_tinyint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_tinyint(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_smallint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int16_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_smallint(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_int(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int32_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_int(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_bigint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_bigint(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_ts(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_float(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, float *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_float(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_double(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, double *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_double(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, SQL_TIMESTAMP_STRUCT *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_timestamp(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst) {
|
||||
const char *utf8 = NULL;
|
||||
TSDB_CONV_CODE code = tsdb_conv(cnv, buffer, src, slen, &utf8, NULL);
|
||||
if (code) return code;
|
||||
code = tsdb_chars_to_timestamp_ts(utf8, sizeof(utf8), dst);
|
||||
tsdb_conv_free(cnv, utf8, buffer, src);
|
||||
return code;
|
||||
}
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, const char **dst, size_t *dlen) {
|
||||
if (!cnv) return TSDB_CONV_NOT_AVAIL;
|
||||
|
||||
char *buf;
|
||||
size_t blen;
|
||||
if (cnv->direct) {
|
||||
if (src[slen]=='\0') { // access violation?
|
||||
*dst = src;
|
||||
if (dlen) *dlen = slen;
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
blen = slen + 1;
|
||||
} else {
|
||||
blen = (slen + 1) * 4;
|
||||
}
|
||||
|
||||
buf = stack_buffer_alloc(buffer, blen);
|
||||
if (!buf) {
|
||||
buf = (char*)malloc(blen);
|
||||
if (!buf) return TSDB_CONV_OOM;
|
||||
}
|
||||
|
||||
if (cnv->direct) {
|
||||
size_t n = slen;
|
||||
DASSERT(blen > n);
|
||||
memcpy(buf, src, n);
|
||||
buf[n] = '\0';
|
||||
*dst = buf;
|
||||
if (dlen) *dlen = n;
|
||||
return TSDB_CONV_OK;
|
||||
}
|
||||
|
||||
const char *orig_s = src;
|
||||
char *orig_d = buf;
|
||||
size_t orig_blen = blen;
|
||||
|
||||
TSDB_CONV_CODE code;
|
||||
size_t r = iconv(cnv->cnv, (char**)&src, &slen, &buf, &blen);
|
||||
do {
|
||||
if (r==(size_t)-1) {
|
||||
switch(errno) {
|
||||
case E2BIG: {
|
||||
code = TSDB_CONV_SRC_TOO_LARGE;
|
||||
} break;
|
||||
case EILSEQ: {
|
||||
code = TSDB_CONV_SRC_BAD_SEQ;
|
||||
} break;
|
||||
case EINVAL: {
|
||||
code = TSDB_CONV_SRC_INCOMPLETE;
|
||||
} break;
|
||||
default: {
|
||||
code = TSDB_CONV_SRC_GENERAL;
|
||||
} break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (slen) {
|
||||
code = TSDB_CONV_TRUNC;
|
||||
break;
|
||||
}
|
||||
DASSERT(blen);
|
||||
*buf = '\0';
|
||||
*dst = orig_d;
|
||||
if (dlen) *dlen = orig_blen - blen;
|
||||
return TSDB_CONV_OK;
|
||||
} while (0);
|
||||
|
||||
if (orig_d!=(char*)orig_s && !is_owned_by_stack_buffer(buffer, orig_d)) free(orig_d);
|
||||
return code;
|
||||
}
|
||||
|
||||
void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src) {
|
||||
if (ptr!=src && !is_owned_by_stack_buffer(buffer, ptr)) free((char*)ptr);
|
||||
}
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _todbc_conv_h_
|
||||
#define _todbc_conv_h_
|
||||
|
||||
#include "os.h"
|
||||
#include <iconv.h>
|
||||
#include <sql.h>
|
||||
|
||||
|
||||
typedef enum {
|
||||
TSDB_CONV_OK = 0,
|
||||
TSDB_CONV_NOT_AVAIL,
|
||||
TSDB_CONV_OOM,
|
||||
TSDB_CONV_OOR,
|
||||
TSDB_CONV_TRUNC_FRACTION,
|
||||
TSDB_CONV_TRUNC,
|
||||
TSDB_CONV_CHAR_NOT_NUM,
|
||||
TSDB_CONV_CHAR_NOT_TS,
|
||||
TSDB_CONV_NOT_VALID_TS,
|
||||
TSDB_CONV_GENERAL,
|
||||
TSDB_CONV_BAD_CHAR,
|
||||
TSDB_CONV_SRC_TOO_LARGE,
|
||||
TSDB_CONV_SRC_BAD_SEQ,
|
||||
TSDB_CONV_SRC_INCOMPLETE,
|
||||
TSDB_CONV_SRC_GENERAL,
|
||||
} TSDB_CONV_CODE;
|
||||
|
||||
const char* tsdb_conv_code_str(TSDB_CONV_CODE code);
|
||||
|
||||
typedef struct stack_buffer_s stack_buffer_t;
|
||||
struct stack_buffer_s {
|
||||
char buf[1024*16];
|
||||
size_t next;
|
||||
};
|
||||
|
||||
char* stack_buffer_alloc(stack_buffer_t *buffer, size_t bytes);
|
||||
int is_owned_by_stack_buffer(stack_buffer_t *buffer, const char *ptr);
|
||||
|
||||
typedef struct tsdb_conv_s tsdb_conv_t;
|
||||
tsdb_conv_t* tsdb_conv_direct(); // get a non-conversion-converter
|
||||
tsdb_conv_t* tsdb_conv_open(const char *from_enc, const char *to_enc);
|
||||
void tsdb_conv_close(tsdb_conv_t *cnv);
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_write(tsdb_conv_t *cnv, const char *src, size_t *slen, char *dst, size_t *dlen);
|
||||
TSDB_CONV_CODE tsdb_conv_write_int64(tsdb_conv_t *cnv, int64_t val, char *dst, size_t *dlen);
|
||||
TSDB_CONV_CODE tsdb_conv_write_double(tsdb_conv_t *cnv, double val, char *dst, size_t *dlen);
|
||||
TSDB_CONV_CODE tsdb_conv_write_timestamp(tsdb_conv_t *cnv, SQL_TIMESTAMP_STRUCT val, char *dst, size_t *dlen);
|
||||
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_bit(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_tinyint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_smallint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int16_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_int(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int32_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_bigint(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_float(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, float *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_double(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, double *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, SQL_TIMESTAMP_STRUCT *dst);
|
||||
TSDB_CONV_CODE tsdb_conv_chars_to_timestamp_ts(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_conv(tsdb_conv_t *cnv, stack_buffer_t *buffer, const char *src, size_t slen, const char **dst, size_t *dlen);
|
||||
void tsdb_conv_free(tsdb_conv_t *cnv, const char *ptr, stack_buffer_t *buffer, const char *src);
|
||||
|
||||
|
||||
TSDB_CONV_CODE tsdb_int64_to_bit(int64_t src, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_tinyint(int64_t src, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_smallint(int64_t src, int16_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_int(int64_t src, int32_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_bigint(int64_t src, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_ts(int64_t src, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_float(int64_t src, float *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_double(int64_t src, double *dst);
|
||||
TSDB_CONV_CODE tsdb_int64_to_char(int64_t src, char *dst, size_t dlen);
|
||||
|
||||
TSDB_CONV_CODE tsdb_double_to_bit(double src, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_tinyint(double src, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_smallint(double src, int16_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_int(double src, int32_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_bigint(double src, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_ts(double src, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_double_to_char(double src, char *dst, size_t dlen);
|
||||
|
||||
TSDB_CONV_CODE tsdb_timestamp_to_char(SQL_TIMESTAMP_STRUCT src, char *dst, size_t dlen);
|
||||
|
||||
TSDB_CONV_CODE tsdb_chars_to_bit(const char *src, size_t smax, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_tinyint(const char *src, size_t smax, int8_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_smallint(const char *src, size_t smax, int16_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_int(const char *src, size_t smax, int32_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_bigint(const char *src, size_t smax, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_ts(const char *src, size_t smax, int64_t *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_float(const char *src, size_t smax, float *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_double(const char *src, size_t smax, double *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_timestamp(const char *src, size_t smax, SQL_TIMESTAMP_STRUCT *dst);
|
||||
TSDB_CONV_CODE tsdb_chars_to_char(const char *src, size_t smax, char *dst, size_t dmax);
|
||||
|
||||
#endif // _todbc_conv_h_
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _TODBC_FLEX_H_
|
||||
#define _TODBC_FLEX_H_
|
||||
|
||||
typedef struct conn_val_s conn_val_t;
|
||||
struct conn_val_s {
|
||||
char *key;
|
||||
char *dsn;
|
||||
char *uid;
|
||||
char *pwd;
|
||||
char *db;
|
||||
char *server;
|
||||
char *svr_enc;
|
||||
char *cli_enc;
|
||||
};
|
||||
|
||||
|
||||
void conn_val_reset(conn_val_t *val);
|
||||
int todbc_parse_conn_string(const char *conn, conn_val_t *val);
|
||||
|
||||
#endif // _TODBC_FLEX_H_
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#ifndef _todbc_log_h_
|
||||
#define _todbc_log_h_
|
||||
|
||||
#include "os.h"
|
||||
|
||||
#define D(fmt, ...) \
|
||||
fprintf(stderr, \
|
||||
"%s[%d]:%s() " fmt "\n", \
|
||||
basename((char*)__FILE__), __LINE__, __func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define DASSERT(statement) \
|
||||
do { \
|
||||
if (statement) break; \
|
||||
D("Assertion failure: %s", #statement); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#define DASSERTX(statement, fmt, ...) \
|
||||
do { \
|
||||
if (statement) break; \
|
||||
D("Assertion failure: %s, " fmt "", #statement, ##__VA_ARGS__); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#endif // _todbc_log_h_
|
||||
|
|
@ -0,0 +1,165 @@
|
|||
%{
|
||||
#include "todbc_flex.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define strncasecmp _strnicmp
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#define PUSH_STATE(state) yy_push_state(state, yyscanner)
|
||||
#define POP_STATE() yy_pop_state(yyscanner)
|
||||
|
||||
#define CHG_STATE(state) \
|
||||
do { \
|
||||
yy_pop_state(yyscanner); \
|
||||
yy_push_state(state, yyscanner); \
|
||||
} while (0)
|
||||
|
||||
#define TOP_STATE(top) \
|
||||
do { \
|
||||
yy_push_state(INITIAL, yyscanner); \
|
||||
top = yy_top_state(yyscanner); \
|
||||
yy_pop_state(yyscanner); \
|
||||
} while (0)
|
||||
|
||||
#define UNPUT() \
|
||||
do { \
|
||||
while (yyleng) unput(yytext[yyleng-1]); \
|
||||
} while (0)
|
||||
|
||||
#define set_key() \
|
||||
do { \
|
||||
free(yyextra->key); \
|
||||
yyextra->key = strdup(yytext); \
|
||||
} while (0)
|
||||
|
||||
#define set_val() \
|
||||
do { \
|
||||
if (!yyextra->key) break; \
|
||||
if (strcasecmp(yyextra->key, "DSN")==0) { \
|
||||
free(yyextra->dsn); \
|
||||
yyextra->dsn = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "UID")==0) { \
|
||||
free(yyextra->uid); \
|
||||
yyextra->uid = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "PWD")==0) { \
|
||||
free(yyextra->pwd); \
|
||||
yyextra->pwd = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "DB")==0) { \
|
||||
free(yyextra->db); \
|
||||
yyextra->pwd = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "Server")==0) { \
|
||||
free(yyextra->server); \
|
||||
yyextra->server = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "SERVER_ENC")==0) { \
|
||||
free(yyextra->svr_enc); \
|
||||
yyextra->svr_enc = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
if (strcasecmp(yyextra->key, "CLIENT_ENC")==0) { \
|
||||
free(yyextra->cli_enc); \
|
||||
yyextra->cli_enc = strdup(yytext); \
|
||||
break; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
%}
|
||||
|
||||
%option prefix="todbc_yy"
|
||||
%option extra-type="conn_val_t *"
|
||||
%option nounistd
|
||||
%option never-interactive
|
||||
%option reentrant
|
||||
%option noyywrap
|
||||
%option noinput nounput
|
||||
%option debug verbose
|
||||
%option stack
|
||||
%option nodefault
|
||||
%option warn
|
||||
%option perf-report
|
||||
%option 8bit
|
||||
|
||||
%x KEY EQ BRACE1 BRACE2 VAL
|
||||
|
||||
%%
|
||||
<<EOF>> { int state; TOP_STATE(state);
|
||||
if (state == INITIAL) yyterminate();
|
||||
if (state == VAL) yyterminate();
|
||||
return -1; }
|
||||
[[:space:]]+ { }
|
||||
[[:alnum:]_]+ { set_key(); PUSH_STATE(KEY); }
|
||||
.|\n { return -1; }
|
||||
|
||||
<KEY>[[:space:]]+ { }
|
||||
<KEY>[=] { CHG_STATE(EQ); }
|
||||
<KEY>.|\n { return -1; }
|
||||
|
||||
<EQ>[[:space:]]+ { }
|
||||
<EQ>[^][{}(),;?*=!@/\\\n[:space:]]+ { set_val(); CHG_STATE(VAL); }
|
||||
<EQ>[{] { CHG_STATE(BRACE1); }
|
||||
<EQ>.|\n { return -1; }
|
||||
|
||||
<BRACE1>[^{}\n]+ { set_val(); CHG_STATE(BRACE2); }
|
||||
<BRACE1>.|\n { return -1; }
|
||||
|
||||
<BRACE2>[[:space:]]+ { }
|
||||
<BRACE2>[}] { CHG_STATE(VAL); }
|
||||
<BRACE2>.|\n { return -1; }
|
||||
|
||||
<VAL>[;] { POP_STATE(); }
|
||||
<VAL>.|\n { return -1; }
|
||||
%%
|
||||
|
||||
int todbc_parse_conn_string(const char *conn, conn_val_t *val) {
|
||||
yyscan_t arg = {0};
|
||||
yylex_init(&arg);
|
||||
yyset_debug(0, arg);
|
||||
yyset_extra(val, arg);
|
||||
yy_scan_string(conn, arg);
|
||||
int ret =yylex(arg);
|
||||
yylex_destroy(arg);
|
||||
if (val->key) free(val->key); val->key = NULL;
|
||||
if (ret) {
|
||||
conn_val_reset(val);
|
||||
}
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
void conn_val_reset(conn_val_t *val) {
|
||||
if (val->key) {
|
||||
free(val->key); val->key = NULL;
|
||||
}
|
||||
if (val->dsn) {
|
||||
free(val->dsn); val->dsn = NULL;
|
||||
}
|
||||
if (val->uid) {
|
||||
free(val->uid); val->uid = NULL;
|
||||
}
|
||||
if (val->pwd) {
|
||||
free(val->pwd); val->pwd = NULL;
|
||||
}
|
||||
if (val->db) {
|
||||
free(val->db); val->db = NULL;
|
||||
}
|
||||
if (val->server) {
|
||||
free(val->server); val->server = NULL;
|
||||
}
|
||||
if (val->svr_enc) {
|
||||
free(val->svr_enc); val->svr_enc = NULL;
|
||||
}
|
||||
if (val->cli_enc) {
|
||||
free(val->cli_enc); val->cli_enc = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -14,14 +14,10 @@
|
|||
*/
|
||||
|
||||
#include "todbc_util.h"
|
||||
|
||||
#include "iconv.h"
|
||||
|
||||
#include <sql.h>
|
||||
#include <sqltypes.h>
|
||||
#include "todbc_log.h"
|
||||
#include <iconv.h>
|
||||
#include <sqlext.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
const char* sql_sql_type(int type) {
|
||||
switch (type) {
|
||||
|
@ -111,39 +107,6 @@ int is_valid_sql_sql_type(int type) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
int string_conv(const char *fromcode, const char *tocode,
|
||||
const unsigned char *src, size_t sbytes,
|
||||
unsigned char *dst, size_t dbytes,
|
||||
size_t *consumed, size_t *generated)
|
||||
{
|
||||
if (consumed) *consumed = 0;
|
||||
if (generated) *generated = 0;
|
||||
|
||||
if (dbytes <= 0) return -1;
|
||||
dst[0] = '\0';
|
||||
|
||||
iconv_t conv = iconv_open(tocode, fromcode);
|
||||
if (!conv) return -1;
|
||||
|
||||
int r = 0;
|
||||
do {
|
||||
char *s = (char*)src;
|
||||
char *d = (char*)dst;
|
||||
size_t sl = sbytes;
|
||||
size_t dl = dbytes;
|
||||
|
||||
r = iconv(conv, &s, &sl, &d, &dl);
|
||||
*d = '\0';
|
||||
|
||||
if (consumed) *consumed = sbytes - sl;
|
||||
if (generated) *generated = dbytes - dl;
|
||||
|
||||
} while (0);
|
||||
|
||||
iconv_close(conv);
|
||||
return r;
|
||||
}
|
||||
|
||||
int utf8_chars(const char *src)
|
||||
{
|
||||
const char *fromcode = "UTF-8";
|
||||
|
@ -161,78 +124,6 @@ int utf8_chars(const char *src)
|
|||
|
||||
size_t chars = (sizeof(buf) - dlen) / 2;
|
||||
iconv_close(conv);
|
||||
return chars;
|
||||
}
|
||||
|
||||
unsigned char* utf8_to_ucs4le(const char *utf8, size_t *chars)
|
||||
{
|
||||
const char *tocode = "UCS-4LE";
|
||||
const char *fromcode = "UTF-8";
|
||||
|
||||
iconv_t conv = iconv_open(tocode, fromcode);
|
||||
if (!conv) return NULL;
|
||||
|
||||
unsigned char *ucs4le = NULL;
|
||||
|
||||
do {
|
||||
size_t slen = strlen(utf8);
|
||||
size_t dlen = slen * 4;
|
||||
|
||||
ucs4le = (unsigned char*)malloc(dlen+1);
|
||||
if (!ucs4le) break;
|
||||
|
||||
char *src = (char*)utf8;
|
||||
char *dst = (char*)ucs4le;
|
||||
size_t s = slen;
|
||||
size_t d = dlen;
|
||||
iconv(conv, &src, &s, &dst, &d);
|
||||
dst[0] = '\0';
|
||||
|
||||
if (chars) *chars = (dlen - d) / 4;
|
||||
} while (0);
|
||||
|
||||
iconv_close(conv);
|
||||
return ucs4le;
|
||||
}
|
||||
|
||||
char* ucs4le_to_utf8(const unsigned char *ucs4le, size_t slen, size_t *chars)
|
||||
{
|
||||
const char *fromcode = "UCS-4LE";
|
||||
const char *tocode = "UTF-8";
|
||||
|
||||
iconv_t conv = iconv_open(tocode, fromcode);
|
||||
if (!conv) return NULL;
|
||||
|
||||
char *utf8 = NULL;
|
||||
|
||||
do {
|
||||
size_t dlen = slen;
|
||||
|
||||
utf8 = (char*)malloc(dlen+1);
|
||||
if (!utf8) break;
|
||||
|
||||
char *dst = utf8;
|
||||
char *src = (char*)ucs4le;
|
||||
size_t s = slen;
|
||||
size_t d = dlen;
|
||||
iconv(conv, &src, &s, &dst, &d);
|
||||
dst[0] = '\0';
|
||||
|
||||
if (chars) *chars = (slen - s) / 4;
|
||||
} while (0);
|
||||
|
||||
iconv_close(conv);
|
||||
return utf8;
|
||||
}
|
||||
|
||||
SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes)
|
||||
{
|
||||
size_t dlen = chs * 4;
|
||||
SQLCHAR *dst = (SQLCHAR*)malloc(dlen + 1);
|
||||
if (!dst) return NULL;
|
||||
|
||||
string_conv("UCS-2LE", "UTF-8", (const unsigned char*)wchars, chs * sizeof(*wchars), dst, dlen + 1, NULL, bytes);
|
||||
|
||||
return dst;
|
||||
return (int)chars;
|
||||
}
|
||||
|
||||
|
|
|
@ -16,33 +16,10 @@
|
|||
#ifndef _TODBC_UTIL_H_
|
||||
#define _TODBC_UTIL_H_
|
||||
|
||||
#include <libgen.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "os.h"
|
||||
|
||||
#include <sql.h>
|
||||
|
||||
#define D(fmt, ...) \
|
||||
fprintf(stderr, \
|
||||
"%s[%d]:%s() " fmt "\n", \
|
||||
basename((char*)__FILE__), __LINE__, __func__, \
|
||||
##__VA_ARGS__)
|
||||
|
||||
#define DASSERT(statement) \
|
||||
do { \
|
||||
if (statement) break; \
|
||||
D("Assertion failure: %s", #statement); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
#define DASSERTX(statement, fmt, ...) \
|
||||
do { \
|
||||
if (statement) break; \
|
||||
D("Assertion failure: %s, " fmt "", #statement, ##__VA_ARGS__); \
|
||||
abort(); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#include <sqltypes.h>
|
||||
|
||||
const char* sql_sql_type(int type);
|
||||
const char* sql_c_type(int type);
|
||||
|
@ -50,14 +27,7 @@ const char* sql_c_type(int type);
|
|||
int is_valid_sql_c_type(int type);
|
||||
int is_valid_sql_sql_type(int type);
|
||||
|
||||
int string_conv(const char *fromcode, const char *tocode,
|
||||
const unsigned char *src, size_t sbytes,
|
||||
unsigned char *dst, size_t dbytes,
|
||||
size_t *consumed, size_t *generated);
|
||||
int utf8_chars(const char *src);
|
||||
|
||||
unsigned char* utf8_to_ucs4le(const char *utf8, size_t *chars);
|
||||
char* ucs4le_to_utf8(const unsigned char *ucs4le, size_t slen, size_t *chars);
|
||||
SQLCHAR* wchars_to_chars(const SQLWCHAR *wchars, size_t chs, size_t *bytes);
|
||||
|
||||
#endif // _TODBC_UTIL_H_
|
||||
|
||||
|
|
|
@ -1,7 +1,18 @@
|
|||
PROJECT(TDengine)
|
||||
|
||||
IF (TD_LINUX)
|
||||
AUX_SOURCE_DIRECTORY(. SRC)
|
||||
# AUX_SOURCE_DIRECTORY(. SRC)
|
||||
ADD_EXECUTABLE(tcodbc main.c)
|
||||
TARGET_LINK_LIBRARIES(tcodbc odbc)
|
||||
ADD_EXECUTABLE(tconv tconv.c)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_64)
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /GL")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /GL")
|
||||
# AUX_SOURCE_DIRECTORY(. SRC)
|
||||
ADD_EXECUTABLE(tcodbc main.c)
|
||||
TARGET_LINK_LIBRARIES(tcodbc odbc32 odbccp32 user32 legacy_stdio_definitions os)
|
||||
ADD_EXECUTABLE(tconv tconv.c)
|
||||
TARGET_LINK_LIBRARIES(tconv tutil)
|
||||
ENDIF ()
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
P:drop database if exists m;
|
||||
P:create database m;
|
||||
P:use m;
|
||||
|
||||
P:drop table if exists t;
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1));
|
||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00', 0, 1);
|
||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.001', 1, 2);
|
||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.002', '你', '好');
|
||||
P:insert into t (ts, blob, name) values('2020-10-10 00:00:00.003', 'abc', 'd');
|
||||
P:select * from t;
|
||||
|
|
@ -1,14 +1,38 @@
|
|||
#include "../src/todbc_log.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "os.h"
|
||||
#endif
|
||||
#include <sql.h>
|
||||
#include <sqlext.h>
|
||||
#include <odbcinst.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "os.h"
|
||||
#define CHK_TEST(statement) \
|
||||
do { \
|
||||
D("testing: %s", #statement); \
|
||||
int r = (statement); \
|
||||
if (r) { \
|
||||
D("testing failed: %s", #statement); \
|
||||
return 1; \
|
||||
} \
|
||||
} while (0);
|
||||
|
||||
// static const char *dsn = "TAOS_DSN";
|
||||
// static const char *uid = "root";
|
||||
// static const char *pwd = "taosdata";
|
||||
typedef struct db_column_s db_column_t;
|
||||
struct db_column_s {
|
||||
SQLSMALLINT nameLength;
|
||||
char name[4096]; // seems enough
|
||||
SQLSMALLINT dataType;
|
||||
SQLULEN columnSize;
|
||||
SQLSMALLINT decimalDigits;
|
||||
SQLSMALLINT nullable;
|
||||
};
|
||||
|
||||
static db_column_t *columns = NULL;
|
||||
|
||||
typedef struct data_s data_t;
|
||||
struct data_s {
|
||||
|
@ -37,7 +61,7 @@ static const char *pro_stmts[] = {
|
|||
// "drop database db"
|
||||
};
|
||||
|
||||
#define CHK_RESULT(r, ht, h) \
|
||||
#define CHK_RESULT(r, ht, h, fmt, ...) \
|
||||
do { \
|
||||
if (r==0) break; \
|
||||
SQLCHAR ss[10]; \
|
||||
|
@ -48,23 +72,149 @@ do {
|
|||
es[0] = '\0'; \
|
||||
SQLRETURN ret = SQLGetDiagRec(ht, h, 1, ss, &ne, es, sizeof(es), &n); \
|
||||
if (ret) break; \
|
||||
fprintf(stderr, "%s%s\n", ss, es); \
|
||||
D("[%s]%s: " fmt "", ss, es, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static int open_connect(const char *dsn, const char *uid, const char *pwd, SQLHENV *pEnv, SQLHDBC *pConn) {
|
||||
SQLRETURN r;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
r = SQLAllocEnv(&env);
|
||||
if (r!=SQL_SUCCESS) return 1;
|
||||
do {
|
||||
r = SQLAllocConnect(env, &conn);
|
||||
CHK_RESULT(r, SQL_HANDLE_ENV, env, "");
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
do {
|
||||
r = SQLConnect(conn, (SQLCHAR*)dsn, (SQLSMALLINT)(dsn ? strlen(dsn) : 0),
|
||||
(SQLCHAR*)uid, (SQLSMALLINT)(uid ? strlen(uid) : 0),
|
||||
(SQLCHAR*)pwd, (SQLSMALLINT)(pwd ? strlen(pwd) : 0));
|
||||
CHK_RESULT(r, SQL_HANDLE_DBC, conn, "");
|
||||
if (r==SQL_SUCCESS) {
|
||||
*pEnv = env;
|
||||
*pConn = conn;
|
||||
return 0;
|
||||
}
|
||||
} while (0);
|
||||
SQLFreeConnect(conn);
|
||||
} while (0);
|
||||
SQLFreeEnv(env);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int open_driver_connect(const char *connstr, SQLHENV *pEnv, SQLHDBC *pConn) {
|
||||
SQLRETURN r;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
r = SQLAllocEnv(&env);
|
||||
if (r!=SQL_SUCCESS) return 1;
|
||||
do {
|
||||
r = SQLAllocConnect(env, &conn);
|
||||
CHK_RESULT(r, SQL_HANDLE_ENV, env, "");
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
do {
|
||||
SQLCHAR buf[4096];
|
||||
SQLSMALLINT blen = 0;
|
||||
SQLHDBC ConnectionHandle = conn;
|
||||
SQLHWND WindowHandle = NULL;
|
||||
SQLCHAR * InConnectionString = (SQLCHAR*)connstr;
|
||||
SQLSMALLINT StringLength1 = (SQLSMALLINT)(connstr ? strlen(connstr) : 0);
|
||||
SQLCHAR * OutConnectionString = buf;
|
||||
SQLSMALLINT BufferLength = sizeof(buf);
|
||||
SQLSMALLINT * StringLength2Ptr = &blen;
|
||||
SQLUSMALLINT DriverCompletion = SQL_DRIVER_NOPROMPT;
|
||||
r = SQLDriverConnect(ConnectionHandle, WindowHandle, InConnectionString,
|
||||
StringLength1, OutConnectionString, BufferLength,
|
||||
StringLength2Ptr, DriverCompletion);
|
||||
CHK_RESULT(r, SQL_HANDLE_DBC, conn, "");
|
||||
if (r==SQL_SUCCESS) {
|
||||
*pEnv = env;
|
||||
*pConn = conn;
|
||||
return 0;
|
||||
}
|
||||
} while (0);
|
||||
SQLFreeConnect(conn);
|
||||
} while (0);
|
||||
SQLFreeEnv(env);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static SQLRETURN traverse_cols(SQLHSTMT stmt, SQLSMALLINT cols) {
|
||||
SQLRETURN r = SQL_ERROR;
|
||||
for (SQLSMALLINT i=0; i<cols; ++i) {
|
||||
db_column_t column = {0};
|
||||
r = SQLDescribeCol(stmt, (SQLUSMALLINT)(i+1), (SQLCHAR*)column.name,
|
||||
(SQLSMALLINT)sizeof(column.name), &column.nameLength,
|
||||
&column.dataType, &column.columnSize,
|
||||
&column.decimalDigits, &column.nullable);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
D("col%02d:[%s]%d,type:[%d],colSize:[%"PRId64"],decimalDigits:[%d],nullable:[%d]",
|
||||
i+1, column.name, column.nameLength, column.dataType, column.columnSize,
|
||||
column.decimalDigits, column.nullable);
|
||||
db_column_t *col = (db_column_t*)realloc(columns, (size_t)(i+1)*sizeof(*col));
|
||||
if (!col) {
|
||||
D("out of memory");
|
||||
return SQL_ERROR;
|
||||
}
|
||||
col[i] = column;
|
||||
columns = col;
|
||||
}
|
||||
return SQL_SUCCESS;
|
||||
}
|
||||
|
||||
static int do_statement(SQLHSTMT stmt, const char *statement) {
|
||||
SQLRETURN r = 0;
|
||||
do {
|
||||
fprintf(stderr, "prepare [%s]\n", statement);
|
||||
r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement));
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
r = SQLExecDirect(stmt, (SQLCHAR*)statement, SQL_NTS);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: [%s]", statement);
|
||||
if (r) break;
|
||||
fprintf(stderr, "execute [%s]\n", statement);
|
||||
r = SQLExecute(stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
SQLSMALLINT cols = 0;
|
||||
r = SQLNumResultCols(stmt, &cols);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
if (r) break;
|
||||
fprintf(stderr, "done\n");
|
||||
if (cols <= 0) break;
|
||||
r = traverse_cols(stmt, cols);
|
||||
char buf[4096];
|
||||
while (1) {
|
||||
SQLRETURN r = SQLFetch(stmt);
|
||||
if (r==SQL_NO_DATA) break;
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
for (size_t i=0; i<cols; ++i) {
|
||||
SQLLEN soi = 0;
|
||||
r = SQLGetData(stmt, (SQLUSMALLINT)(i+1), SQL_C_CHAR, buf, sizeof(buf), &soi);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
if (r) {
|
||||
if (r!=SQL_SUCCESS_WITH_INFO) {
|
||||
if (i>0) fprintf(stdout, "\n");
|
||||
return r;
|
||||
}
|
||||
}
|
||||
if (soi==SQL_NULL_DATA) {
|
||||
fprintf(stdout, "%snull", i==0?"":",");
|
||||
} else {
|
||||
fprintf(stdout, "%s\"%s\"", i==0?"":",", buf);
|
||||
}
|
||||
}
|
||||
fprintf(stdout, "\n");
|
||||
}
|
||||
|
||||
// r = SQLFetch(stmt);
|
||||
// if (r==SQL_NO_DATA) {
|
||||
// D("..........");
|
||||
// r = SQL_SUCCESS;
|
||||
// break;
|
||||
// }
|
||||
// CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
// if (r) break;
|
||||
// r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement));
|
||||
// CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "");
|
||||
// if (r) break;
|
||||
// r = SQLExecute(stmt);
|
||||
// CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
// if (r) break;
|
||||
} while (0);
|
||||
fprintf(stderr, "r: [%x][%d]\n", r, r);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -74,158 +224,450 @@ static int do_insert(SQLHSTMT stmt, data_t data) {
|
|||
SQLLEN lblob;
|
||||
|
||||
const char *statement = "insert into t values (?, ?, ?, ?, ?, ?, ?, ?, ?,?)";
|
||||
int ignored = 0;
|
||||
#define ignored 0
|
||||
|
||||
do {
|
||||
fprintf(stderr, "prepare [%s]\n", statement);
|
||||
r = SQLPrepare(stmt, (SQLCHAR*)statement, strlen(statement));
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
r = SQLPrepare(stmt, (SQLCHAR*)statement, (SQLINTEGER)strlen(statement));
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 1 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_TIMESTAMP, ignored, ignored, &data.ts, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 2 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_BIT, SQL_BIT, ignored, ignored, &data.b, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 3 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_TINYINT, SQL_TINYINT, ignored, ignored, &data.v1, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 4 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_SHORT, SQL_SMALLINT, ignored, ignored, &data.v2, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 5 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, ignored, ignored, &data.v4, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 6 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_SBIGINT, SQL_BIGINT, ignored, ignored, &data.v8, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 7 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_FLOAT, SQL_FLOAT, ignored, ignored, &data.f4, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 8 [%s]\n", statement);
|
||||
r = SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DOUBLE, ignored, ignored, &data.f8, ignored, NULL);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 9 [%s]\n", statement);
|
||||
lbin = SQL_NTS;
|
||||
r = SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_VARBINARY, sizeof(data.bin)-1, ignored, &data.bin, ignored, &lbin);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "bind 10 [%s]\n", statement);
|
||||
lblob = SQL_NTS;
|
||||
r = SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, sizeof(data.blob)-1, ignored, &data.blob, ignored, &lblob);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
fprintf(stderr, "execute [%s]\n", statement);
|
||||
r = SQLExecute(stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_STMT, stmt, "statement: %s", statement);
|
||||
if (r) break;
|
||||
|
||||
// ts += 1;
|
||||
// v = 2;
|
||||
// fprintf(stderr, "execute [%s]\n", statement);
|
||||
// r = SQLExecute(stmt);
|
||||
// if (r) break;
|
||||
|
||||
fprintf(stderr, "done\n");
|
||||
} while (0);
|
||||
fprintf(stderr, "r: [%x][%d]\n", r, r);
|
||||
|
||||
#undef ignored
|
||||
return r;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
if (argc < 4) return 1;
|
||||
const char *dsn = argv[1];
|
||||
const char *uid = argv[2];
|
||||
const char *pwd = argv[3];
|
||||
SQLRETURN r;
|
||||
static int test1(const char *dsn, const char *uid, const char *pwd) {
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
r = SQLAllocEnv(&env);
|
||||
if (r!=SQL_SUCCESS) return 1;
|
||||
int n = open_connect(dsn, uid, pwd, &env, &conn);
|
||||
if (n) return 1;
|
||||
|
||||
int ok = 0;
|
||||
do {
|
||||
r = SQLAllocConnect(env, &conn);
|
||||
CHK_RESULT(r, SQL_HANDLE_ENV, env);
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
SQLHSTMT stmt = {0};
|
||||
r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
do {
|
||||
r = SQLConnect(conn, (SQLCHAR*)dsn, strlen(dsn),
|
||||
(SQLCHAR*)uid, strlen(uid),
|
||||
(SQLCHAR*)pwd, strlen(pwd));
|
||||
CHK_RESULT(r, SQL_HANDLE_DBC, conn);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
if (do_statement(stmt, "drop database if exists db")) {
|
||||
break;
|
||||
}
|
||||
for (size_t i=0; i<sizeof(pre_stmts)/sizeof(pre_stmts[0]); ++i) {
|
||||
n = do_statement(stmt, pre_stmts[i]);
|
||||
if (n) break;
|
||||
}
|
||||
do {
|
||||
data_t data = {0};
|
||||
data.ts = 1591060628001;
|
||||
data.b = 1;
|
||||
data.v1 = 127;
|
||||
data.v2 = 32767;
|
||||
data.v4 = 2147483647;
|
||||
data.v8 = 9223372036854775807;
|
||||
data.f4 = 123.456f;
|
||||
data.f8 = 9999999.999999;
|
||||
memset(data.bin, 0, sizeof(data.bin));
|
||||
memset(data.blob, 0, sizeof(data.blob));
|
||||
snprintf(data.bin, sizeof(data.bin), "hel我lo");
|
||||
snprintf(data.blob, sizeof(data.blob), "world");
|
||||
snprintf(data.blob, sizeof(data.blob), "wo人rld");
|
||||
SQLHSTMT stmt = {0};
|
||||
r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
do {
|
||||
do_statement(stmt, "drop database db");
|
||||
for (size_t i=0; i<sizeof(pre_stmts)/sizeof(pre_stmts[0]); ++i) {
|
||||
r = do_statement(stmt, pre_stmts[i]);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
}
|
||||
do {
|
||||
data_t data = {0};
|
||||
data.ts = 1591060628001;
|
||||
data.b = 1;
|
||||
data.v1 = 127;
|
||||
data.v2 = 32767;
|
||||
data.v4 = 2147483647;
|
||||
data.v8 = 9223372036854775807;
|
||||
data.f4 = 123.456;
|
||||
data.f8 = 9999999.999999;
|
||||
memset(data.bin, 0, sizeof(data.bin));
|
||||
memset(data.blob, 0, sizeof(data.blob));
|
||||
snprintf(data.bin, sizeof(data.bin), "hel我lo");
|
||||
snprintf(data.blob, sizeof(data.blob), "world");
|
||||
snprintf(data.blob, sizeof(data.blob), "wo人rld");
|
||||
SQLHSTMT stmt = {0};
|
||||
r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
do {
|
||||
r = do_insert(stmt, data);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
} while (0);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
|
||||
// r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
// if (r!=SQL_SUCCESS) break;
|
||||
// do {
|
||||
// r = do_insert(stmt, ts++, v++);
|
||||
// if (r!=SQL_SUCCESS) break;
|
||||
// } while (0);
|
||||
// SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
} while (0);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
for (size_t i=0; i<sizeof(pro_stmts)/sizeof(pro_stmts[0]); ++i) {
|
||||
r = do_statement(stmt, pro_stmts[i]);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
}
|
||||
n = do_insert(stmt, data);
|
||||
if (n) break;
|
||||
} while (0);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
|
||||
// r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
// if (r!=SQL_SUCCESS) break;
|
||||
// do {
|
||||
// r = do_insert(stmt, ts++, v++);
|
||||
// if (r!=SQL_SUCCESS) break;
|
||||
// } while (0);
|
||||
// SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
ok = 1;
|
||||
} while (0);
|
||||
SQLDisconnect(conn);
|
||||
if (!ok) break;
|
||||
ok = 0;
|
||||
for (size_t i=0; i<sizeof(pro_stmts)/sizeof(pro_stmts[0]); ++i) {
|
||||
n = do_statement(stmt, pro_stmts[i]);
|
||||
if (n) break;
|
||||
}
|
||||
ok = 1;
|
||||
} while (0);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
} while (0);
|
||||
SQLDisconnect(conn);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeEnv(env);
|
||||
|
||||
return ok ? 0 : 1;
|
||||
}
|
||||
|
||||
int test_statements(const char *dsn, const char *uid, const char *pwd, const char **statements) {
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
int n = open_connect(dsn, uid, pwd, &env, &conn);
|
||||
if (n) return 1;
|
||||
do {
|
||||
SQLHSTMT stmt = {0};
|
||||
r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
if (r!=SQL_SUCCESS) break;
|
||||
const char **p = statements;
|
||||
while (*p) {
|
||||
if (do_statement(stmt, *p)) {
|
||||
r = SQL_ERROR;
|
||||
break;
|
||||
}
|
||||
++p;
|
||||
}
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
} while (0);
|
||||
SQLDisconnect(conn);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeEnv(env);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
int test_driver_connect(const char *connstr) {
|
||||
SQLRETURN r = SQL_SUCCESS;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
int n = open_driver_connect(connstr, &env, &conn);
|
||||
if (n) return 1;
|
||||
SQLDisconnect(conn);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeEnv(env);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
int create_statement(SQLHENV env, SQLHDBC conn, SQLHSTMT *pStmt) {
|
||||
SQLHSTMT stmt = {0};
|
||||
SQLRETURN r = SQLAllocHandle(SQL_HANDLE_STMT, conn, &stmt);
|
||||
CHK_RESULT(r, SQL_HANDLE_DBC, conn, "");
|
||||
if (r==SQL_SUCCESS) {
|
||||
*pStmt = stmt;
|
||||
return 0;
|
||||
}
|
||||
if (r==SQL_SUCCESS_WITH_INFO) {
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int do_statements(SQLHSTMT stmt, const char **statements) {
|
||||
const char **p = statements;
|
||||
while (p && *p) {
|
||||
CHK_TEST(do_statement(stmt, *p));
|
||||
++p;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tests_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt) {
|
||||
const char *statements[] = {
|
||||
"drop database if exists m",
|
||||
"create database m",
|
||||
"use m",
|
||||
// "create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(1), name nchar(1))",
|
||||
"create table t (ts timestamp, b bool)",
|
||||
"insert into t values('2020-10-10 00:00:00', 0)",
|
||||
"insert into t values('2020-10-10 00:00:00.001', 1)",
|
||||
NULL
|
||||
};
|
||||
CHK_TEST(do_statements(stmt, statements));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tests(SQLHENV env, SQLHDBC conn) {
|
||||
SQLHSTMT stmt = {0};
|
||||
CHK_TEST(create_statement(env, conn, &stmt));
|
||||
int r = tests_stmt(env, conn, stmt);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
int test_env(void) {
|
||||
SQLRETURN r;
|
||||
SQLHENV env = {0};
|
||||
r = SQLAllocEnv(&env);
|
||||
if (r!=SQL_SUCCESS) return 1;
|
||||
SQLFreeEnv(env);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_sqls_in_stmt(SQLHENV env, SQLHDBC conn, SQLHSTMT stmt, const char *sqls) {
|
||||
FILE *f = fopen(sqls, "rb");
|
||||
if (!f) {
|
||||
D("failed to open file [%s]", sqls);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int r = 0;
|
||||
while (!feof(f)) {
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
|
||||
ssize_t n = 0;
|
||||
#ifdef _MSC_VER
|
||||
n = taosGetline(&line, &len, f);
|
||||
#else
|
||||
n = getline(&line, &len, f);
|
||||
#endif
|
||||
if (n==-1) break;
|
||||
|
||||
const char *p = NULL;
|
||||
do {
|
||||
if (line[0] == '#') break;
|
||||
if (n>0 && line[n-1] == '\n') line[n-1]='\0';
|
||||
if (n>0 && line[n-1] == '\r') line[n-1]='\0';
|
||||
if (n>1 && line[n-2] == '\r') line[n-2]='\0';
|
||||
p = line;
|
||||
while (isspace(*p)) ++p;
|
||||
|
||||
if (*p==0) break;
|
||||
|
||||
int positive = 1;
|
||||
if (strncmp(p, "N:", 2)==0) {
|
||||
positive = 0;
|
||||
p += 2;
|
||||
} else if (strncmp(p, "P:", 2)==0) {
|
||||
p += 2;
|
||||
}
|
||||
|
||||
D("statement: [%s]", p);
|
||||
r = do_statement(stmt, p);
|
||||
|
||||
if (positive && r==0) break;
|
||||
if (!positive && r) { r = 0; break; }
|
||||
if (positive) return r;
|
||||
D("expecting negative result, but got positive");
|
||||
return -1;
|
||||
} while (0);
|
||||
|
||||
free(line);
|
||||
|
||||
if (r) break;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
int test_sqls_in_conn(SQLHENV env, SQLHDBC conn, const char *sqls) {
|
||||
SQLHSTMT stmt = {0};
|
||||
CHK_TEST(create_statement(env, conn, &stmt));
|
||||
int r = test_sqls_in_stmt(env, conn, stmt, sqls);
|
||||
SQLFreeHandle(SQL_HANDLE_STMT, stmt);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
int test_sqls(const char *dsn, const char *uid, const char *pwd, const char *connstr, const char *sqls) {
|
||||
int r = 0;
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
if (dsn) {
|
||||
CHK_TEST(open_connect(dsn, uid, pwd, &env, &conn));
|
||||
} else {
|
||||
CHK_TEST(open_driver_connect(connstr, &env, &conn));
|
||||
}
|
||||
if (sqls) {
|
||||
r = test_sqls_in_conn(env, conn, sqls);
|
||||
}
|
||||
SQLDisconnect(conn);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeEnv(env);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
void usage(const char *arg0) {
|
||||
fprintf(stdout, "%s usage:\n", arg0);
|
||||
fprintf(stdout, "%s [--dsn <dsn>] [--uid <uid>] [--pwd <pwd>] [--dcs <dcs>] [--sts <sts>]\n", arg0);
|
||||
fprintf(stdout, " --dsn <dsn>: DSN\n");
|
||||
fprintf(stdout, " --uid <uid>: UID\n");
|
||||
fprintf(stdout, " --pwd <pwd>: PWD\n");
|
||||
fprintf(stdout, " --dcs <dcs>: driver connection string\n");
|
||||
fprintf(stdout, " --sts <sts>: file where statements store\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
// if (argc==1) {
|
||||
// CHK_TEST(test_env());
|
||||
// CHK_TEST(test1("TAOS_DSN", "root", "taoxsdata"));
|
||||
// D("Done!");
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
const char *dsn = NULL;
|
||||
const char *uid = NULL;
|
||||
const char *pwd = NULL;
|
||||
const char *dcs = NULL; // driver connection string
|
||||
const char *sts = NULL; // statements file
|
||||
for (size_t i=1; i<argc; ++i) {
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "-h")==0) {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(arg, "--dsn")==0) {
|
||||
++i;
|
||||
if (i>=argc) {
|
||||
D("<dsn> expected but got nothing");
|
||||
return 1;
|
||||
}
|
||||
if (dcs) {
|
||||
D("--dcs has already been specified");
|
||||
return 1;
|
||||
}
|
||||
dsn = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (strcmp(arg, "--uid")==0) {
|
||||
++i;
|
||||
if (i>=argc) {
|
||||
D("<uid> expected but got nothing");
|
||||
return 1;
|
||||
}
|
||||
uid = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (strcmp(arg, "--pwd")==0) {
|
||||
++i;
|
||||
if (i>=argc) {
|
||||
D("<pwd> expected but got nothing");
|
||||
return 1;
|
||||
}
|
||||
pwd = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (strcmp(arg, "--dcs")==0) {
|
||||
++i;
|
||||
if (i>=argc) {
|
||||
D("<dcs> expected but got nothing");
|
||||
return 1;
|
||||
}
|
||||
if (dsn || uid || pwd) {
|
||||
D("either of --dsn/--uid/--pwd has already been specified");
|
||||
return 1;
|
||||
}
|
||||
dcs = argv[i];
|
||||
continue;
|
||||
}
|
||||
if (strcmp(arg, "--sts")==0) {
|
||||
++i;
|
||||
if (i>=argc) {
|
||||
D("<sts> expected but got nothing");
|
||||
return 1;
|
||||
}
|
||||
sts = argv[i];
|
||||
continue;
|
||||
}
|
||||
}
|
||||
CHK_TEST(test_sqls(dsn, uid, pwd, dcs, sts));
|
||||
D("Done!");
|
||||
return 0;
|
||||
|
||||
if (0) {
|
||||
const char *dsn = (argc>1) ? argv[1] : NULL;
|
||||
const char *uid = (argc>2) ? argv[2] : NULL;
|
||||
const char *pwd = (argc>3) ? argv[3] : NULL;
|
||||
const char *connstr = (argc>4) ? argv[4] : NULL;
|
||||
const char *sqls = (argc>5) ? argv[5] : NULL;
|
||||
|
||||
dsn = NULL;
|
||||
uid = NULL;
|
||||
pwd = NULL;
|
||||
connstr = argv[1];
|
||||
sqls = argv[2];
|
||||
if (0) {
|
||||
CHK_TEST(test_env());
|
||||
|
||||
CHK_TEST(test1(dsn, uid, pwd));
|
||||
|
||||
const char *statements[] = {
|
||||
"drop database if exists m",
|
||||
"create database m",
|
||||
"use m",
|
||||
"drop database m",
|
||||
NULL
|
||||
};
|
||||
CHK_TEST(test_statements(dsn, uid, pwd, statements));
|
||||
|
||||
if (connstr)
|
||||
CHK_TEST(test_driver_connect(connstr));
|
||||
|
||||
if (connstr) {
|
||||
SQLHENV env = {0};
|
||||
SQLHDBC conn = {0};
|
||||
CHK_TEST(open_driver_connect(connstr, &env, &conn));
|
||||
int r = tests(env, conn);
|
||||
SQLDisconnect(conn);
|
||||
SQLFreeConnect(conn);
|
||||
SQLFreeEnv(env);
|
||||
if (r) return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((dsn || connstr) && 1) {
|
||||
CHK_TEST(test_sqls(dsn, uid, pwd, connstr, sqls));
|
||||
}
|
||||
|
||||
D("Done!");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,16 +1,17 @@
|
|||
import pyodbc
|
||||
cnxn = pyodbc.connect('DSN=TAOS_DSN;UID=root;PWD=taosdata', autocommit=True)
|
||||
# cnxn = pyodbc.connect('DSN={TAOS_DSN};UID={ root };PWD={ taosdata };HOST={ localhost:6030 }', autocommit=True)
|
||||
cnxn = pyodbc.connect('DSN={TAOS_DSN}; UID=root;PWD=taosdata; HOST=localhost:6030', autocommit=True)
|
||||
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf-8')
|
||||
#cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf-8')
|
||||
#cnxn.setencoding(encoding='utf-8')
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("SELECT * from db.t")
|
||||
row = cursor.fetchone()
|
||||
while row:
|
||||
print(row)
|
||||
row = cursor.fetchone()
|
||||
cursor.close()
|
||||
#cursor = cnxn.cursor()
|
||||
#cursor.execute("SELECT * from db.t")
|
||||
#row = cursor.fetchone()
|
||||
#while row:
|
||||
# print(row)
|
||||
# row = cursor.fetchone()
|
||||
#cursor.close()
|
||||
|
||||
#cursor = cnxn.cursor()
|
||||
#cursor.execute("""
|
||||
|
@ -36,32 +37,32 @@ cursor.execute("create database db");
|
|||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))");
|
||||
cursor.execute("create table db.mt (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(40), blob nchar(10))");
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("insert into db.t values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hello', 'world')")
|
||||
cursor.execute("insert into db.mt values('2020-10-13 06:44:00', 1, 127, 32767, 32768, 32769, 123.456, 789.987, 'hello', 'world')")
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("insert into db.t values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo", "wo哈rld");
|
||||
cursor.execute("insert into db.mt values(?,?,?,?,?,?,?,?,?,?)", "2020-10-13 07:06:00", 0, 127, 32767, 32768, 32769, 123.456, 789.987, "hel后lo", "wo哈rld");
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("SELECT * from db.t")
|
||||
cursor.execute("SELECT * from db.mt")
|
||||
row = cursor.fetchone()
|
||||
while row:
|
||||
print(row)
|
||||
row = cursor.fetchone()
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("drop database if exists db");
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("create database db");
|
||||
cursor.close()
|
||||
#cursor = cnxn.cursor()
|
||||
#cursor.execute("drop database if exists db");
|
||||
#cursor.close()
|
||||
#
|
||||
#cursor = cnxn.cursor()
|
||||
#cursor.execute("create database db");
|
||||
#cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("create table db.t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, bin binary(4), blob nchar(4))");
|
||||
|
@ -118,3 +119,13 @@ while row:
|
|||
row = cursor.fetchone()
|
||||
cursor.close()
|
||||
|
||||
cursor = cnxn.cursor()
|
||||
cursor.execute("create table db.f (ts timestamp, v1 float)")
|
||||
cursor.close()
|
||||
|
||||
params = [ ('2020-10-20 00:00:10', '123.3') ]
|
||||
cursor = cnxn.cursor()
|
||||
cursor.fast_executemany = True
|
||||
cursor.executemany("insert into db.f values (?, ?)", params)
|
||||
cursor.close()
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
P:select * from m.t;
|
|
@ -0,0 +1,4 @@
|
|||
P: select * from db.t;
|
||||
P: select * from db.f;
|
||||
P: select * from db.v;
|
||||
P: select * from db.mt;
|
|
@ -0,0 +1,44 @@
|
|||
P:drop database if exists m;
|
||||
P:create database m;
|
||||
P:use m;
|
||||
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(1), name nchar(1));
|
||||
P:insert into t (ts, b) values('2020-10-10 00:00:00', 0);
|
||||
P:insert into t (ts, b) values('2020-10-10 00:00:00.001', 1);
|
||||
P:insert into t (ts, b) values('2020-10-10 00:00:00.002', 10);
|
||||
P:select * from t;
|
||||
|
||||
P:drop table t;
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(1), name nchar(1));
|
||||
P:insert into t (ts, v1) values('2020-10-10 00:00:00', 0);
|
||||
P:insert into t (ts, v1) values('2020-10-10 00:00:00.001', 1);
|
||||
P:insert into t (ts, v1) values('2020-10-10 00:00:00.002', 10);
|
||||
P:select * from t;
|
||||
|
||||
P:drop table t;
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(1), name nchar(1));
|
||||
P:insert into t (ts, name) values('2020-10-10 00:00:00', 0);
|
||||
P:insert into t (ts, name) values('2020-10-10 00:00:00.001', 1);
|
||||
P:insert into t (ts, name) values('2020-10-10 00:00:00.002', '人');
|
||||
P:insert into t (ts, name) values('2020-10-10 00:00:00.003', 'a');
|
||||
P:select * from t;
|
||||
|
||||
P:drop table t;
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1));
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00', 0);
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.001', 1);
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.002', 'a');
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.003', 'b');
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.004', '人');
|
||||
P:select * from t;
|
||||
|
||||
P:drop table t;
|
||||
P:create table t (ts timestamp, b bool, v1 tinyint, v2 smallint, v4 int, v8 bigint, f4 float, f8 double, blob binary(3), name nchar(1));
|
||||
N:insert into t (ts, blob) values('2020-10-10 00:00:00', '1234');
|
||||
N:insert into t (ts, blob) values('2020-10-10 00:00:00.001', '0000');
|
||||
N:insert into t (ts, blob) values('2020-10-10 00:00:00.002', '人a');
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.003', 'a');
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.004', 'b');
|
||||
P:insert into t (ts, blob) values('2020-10-10 00:00:00.005', '人');
|
||||
P:select * from t;
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
#include "../src/todbc_log.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <iconv.h>
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void usage(const char *arg0);
|
||||
static int do_conv(iconv_t cnv, FILE *fin, FILE *fout);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *from_enc = "UTF-8";
|
||||
const char *to_enc = "UTF-8";
|
||||
const char *dst_file = NULL;
|
||||
const char *src = NULL;
|
||||
#ifdef _MSC_VER
|
||||
from_enc = "CP936";
|
||||
to_enc = "CP936";
|
||||
#endif
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "-h") == 0) {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
} else if (strcmp(arg, "-f") == 0 ) {
|
||||
i += 1;
|
||||
if (i>=argc) {
|
||||
fprintf(stderr, "expecing <from_enc>, but got nothing\n");
|
||||
return 1;
|
||||
}
|
||||
from_enc = argv[i];
|
||||
continue;
|
||||
} else if (strcmp(arg, "-t") == 0 ) {
|
||||
i += 1;
|
||||
if (i>=argc) {
|
||||
fprintf(stderr, "expecing <to_enc>, but got nothing\n");
|
||||
return 1;
|
||||
}
|
||||
to_enc = argv[i];
|
||||
continue;
|
||||
} else if (strcmp(arg, "-o") == 0 ) {
|
||||
i += 1;
|
||||
if (i>=argc) {
|
||||
fprintf(stderr, "expecing <dst_file>, but got nothing\n");
|
||||
return 1;
|
||||
}
|
||||
dst_file = argv[i];
|
||||
continue;
|
||||
} else if (arg[0]=='-') {
|
||||
fprintf(stderr, "unknown argument: [%s]\n", arg);
|
||||
return 1;
|
||||
} else {
|
||||
if (src) {
|
||||
fprintf(stderr, "does not allow multiple files\n");
|
||||
return 1;
|
||||
}
|
||||
src = arg;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
int r = -1;
|
||||
FILE *fin = src ? fopen(src, "rb") : stdin;
|
||||
FILE *fout = dst_file ? fopen(dst_file, "wb") : stdout;
|
||||
iconv_t cnv = iconv_open(to_enc, from_enc);
|
||||
do {
|
||||
if (!fin) {
|
||||
fprintf(stderr, "failed to open file [%s]\n", src);
|
||||
break;
|
||||
}
|
||||
if (!fout) {
|
||||
fprintf(stderr, "failed to open file [%s]\n", dst_file);
|
||||
break;
|
||||
}
|
||||
#ifdef _MSC_VER
|
||||
if (fout == stdout) {
|
||||
r = _setmode(_fileno(fout), _O_BINARY);
|
||||
if (r == -1) {
|
||||
fprintf(stderr, "Cannot set binary mode for output stream: %d[%s]\n", errno, strerror(errno));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (cnv == (iconv_t)-1) {
|
||||
fprintf(stderr, "failed to open conv from [%s] to [%s]: [%s]\n", from_enc, to_enc, strerror(errno));
|
||||
break;
|
||||
}
|
||||
r = do_conv(cnv, fin, fout);
|
||||
iconv_close(cnv);
|
||||
cnv = (iconv_t)-1;
|
||||
} while (0);
|
||||
if (fin && fin != stdin) fclose(fin);
|
||||
if (fout && fout != stdout) fclose(fout);
|
||||
return r ? 1 : 0;
|
||||
}
|
||||
|
||||
static void usage(const char *arg0) {
|
||||
fprintf(stderr, "%s -h | [-f <from_enc>] [-t <to_enc>] [-o <dst file>] [file]\n", arg0);
|
||||
return;
|
||||
}
|
||||
|
||||
#define IN_SIZE (64*1024)
|
||||
#define OUT_SIZE (8*IN_SIZE)
|
||||
static int do_conv(iconv_t cnv, FILE *fin, FILE *fout) {
|
||||
int r = 0;
|
||||
char src[IN_SIZE];
|
||||
size_t slen = sizeof(src);
|
||||
char dst[OUT_SIZE];
|
||||
size_t dlen = sizeof(dst);
|
||||
char *start = src;
|
||||
while (!feof(fin)) {
|
||||
slen = (size_t)(src + sizeof(src) - start);
|
||||
size_t n = fread(start, 1, slen, fin);
|
||||
if (n>0) {
|
||||
char *ss = src;
|
||||
size_t sl = n;
|
||||
while (sl) {
|
||||
char *dd = dst;
|
||||
size_t dn = dlen;
|
||||
size_t v = iconv(cnv, &ss, &sl, &dd, &dn);
|
||||
if (v==(size_t)-1) {
|
||||
int err = errno;
|
||||
if (err == EILSEQ) {
|
||||
fprintf(stderr, "failed to convert: [%s]\n", strerror(err));
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
if (err == EINVAL) {
|
||||
fprintf(stderr, "[%s]\n", strerror(errno));
|
||||
size_t ava = (size_t)(src + sizeof(src) - ss);
|
||||
memcpy(src, ss, ava);
|
||||
start = ss;
|
||||
} else {
|
||||
fprintf(stderr, "internal logic error: [%s]\n", strerror(errno));
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
n = fwrite(dst, 1, (size_t)(dd-dst), fout);
|
||||
if (n<dd-dst) {
|
||||
fprintf(stderr, "failed to write: [%s]\n", strerror(errno));
|
||||
r = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (r) break;
|
||||
}
|
||||
}
|
||||
return r ? -1 : 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
PROJECT(TDengine)
|
||||
|
||||
IF (TD_LINUX)
|
||||
ADD_EXECUTABLE(todbcinst main.c)
|
||||
TARGET_LINK_LIBRARIES(todbcinst odbc odbcinst)
|
||||
ENDIF ()
|
||||
|
||||
IF (TD_WINDOWS_64)
|
||||
ADD_EXECUTABLE(todbcinst main.c)
|
||||
TARGET_LINK_LIBRARIES(todbcinst odbc32 odbccp32 user32 legacy_stdio_definitions os)
|
||||
INSTALL(FILES ${EXECUTABLE_OUTPUT_PATH}/todbcinst.exe DESTINATION .)
|
||||
ENDIF ()
|
|
@ -0,0 +1,165 @@
|
|||
#include "../src/todbc_log.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#include "os.h"
|
||||
#endif
|
||||
#include <odbcinst.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
static void usage(const char *arg0);
|
||||
static int do_install(int i, int argc, char *argv[]);
|
||||
static int do_uninstall(int i, int argc, char *argv[]);
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "-h") == 0) {
|
||||
usage(argv[0]);
|
||||
return 0;
|
||||
} else if (strcmp(arg, "-i") == 0 ) {
|
||||
i = do_install(i + 1, argc, argv);
|
||||
if (i > 0) continue;
|
||||
return i == 0 ? 0 : 1;
|
||||
} else if (strcmp(arg, "-u") == 0 ) {
|
||||
i = do_uninstall(i + 1, argc, argv);
|
||||
if (i > 0) continue;
|
||||
return i == 0 ? 0 : 1;
|
||||
} else {
|
||||
fprintf(stderr, "unknown argument: [%s]\n", arg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usage(const char *arg0) {
|
||||
fprintf(stderr, "%s -h | -i -n [TaosDriverName] -p [TaosDriverPath] | -u [-f] -n [TaosDriverName]\n", arg0);
|
||||
return;
|
||||
}
|
||||
|
||||
static int do_install(int i, int argc, char *argv[]) {
|
||||
const char* driverName = NULL;
|
||||
#ifdef _MSC_VER
|
||||
const char* driverFile = "todbc.dll";
|
||||
#else
|
||||
const char* driverFile = "libtodbc.so";
|
||||
#endif
|
||||
const char* driverPath = NULL;
|
||||
for (; i < argc; ++i) {
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "-n") == 0) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "expecting TaosDriverName, but got nothing\n");
|
||||
return -1;
|
||||
}
|
||||
arg = argv[i];
|
||||
if (strstr(arg, "TAOS") != arg) {
|
||||
fprintf(stderr, "TaosDriverName shall begin with 'TAOS': [%s]\n", arg);
|
||||
return -1;
|
||||
}
|
||||
driverName = arg;
|
||||
} else if (strcmp(arg, "-p") == 0) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "expecting TaosDriverPath, but got nothing\n");
|
||||
return -1;
|
||||
}
|
||||
driverPath = argv[i];
|
||||
} else {
|
||||
fprintf(stderr, "unknown argument: [%s]\n", arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!driverName) {
|
||||
fprintf(stderr, "TaosDriverName not specified\n");
|
||||
return -1;
|
||||
}
|
||||
if (!driverPath) {
|
||||
fprintf(stderr, "TaosDriverPath not specified\n");
|
||||
return -1;
|
||||
}
|
||||
char buf[8192];
|
||||
snprintf(buf, sizeof(buf), "%s%cDriver=%s%cFileUage=0%cConnectFunctions=YYN%c",
|
||||
driverName, 0, driverFile, 0, 0, 0);
|
||||
BOOL ok = 1;
|
||||
DWORD usageCount = 1;
|
||||
char installed[PATH_MAX + 1];
|
||||
WORD len = 0;
|
||||
ok = SQLInstallDriverEx(buf, driverPath, installed, sizeof(installed), &len, ODBC_INSTALL_INQUIRY, &usageCount);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "failed to query TaosDriverName: [%s]\n", driverName);
|
||||
return -1;
|
||||
}
|
||||
int r = 0;
|
||||
#ifdef _MSC_VER
|
||||
r = stricmp(driverPath, installed);
|
||||
#else
|
||||
r = strcasecmp(driverPath, installed);
|
||||
#endif
|
||||
if (r) {
|
||||
fprintf(stderr, "previously installed TaosDriver [%s] has different target path [%s]\n"
|
||||
"it shall be uninstalled before you can install it to different path [%s]\n",
|
||||
driverName, installed, driverPath);
|
||||
return -1;
|
||||
}
|
||||
ok = SQLInstallDriverEx(buf, driverPath, installed, sizeof(installed), &len, ODBC_INSTALL_COMPLETE, &usageCount);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "failed to install TaosDriverName: [%s][%s]\n", driverName, driverPath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fprintf(stderr, "ODBC driver [%s] has been installed in [%s], and UsageCount is now [%d]\n",
|
||||
driverName, driverPath, usageCount);
|
||||
return argc;
|
||||
}
|
||||
|
||||
static int do_uninstall(int i, int argc, char *argv[]) {
|
||||
int forceful = 0;
|
||||
const char* driverName = NULL;
|
||||
for (; i < argc; ++i) {
|
||||
const char *arg = argv[i];
|
||||
if (strcmp(arg, "-f") == 0) {
|
||||
forceful = 1;
|
||||
} else if (strcmp(arg, "-n") == 0) {
|
||||
i += 1;
|
||||
if (i >= argc) {
|
||||
fprintf(stderr, "expecting TaosDriverName, but got nothing\n");
|
||||
return -1;
|
||||
}
|
||||
arg = argv[i];
|
||||
if (strstr(arg, "TAOS") != arg) {
|
||||
fprintf(stderr, "TaosDriverName shall begin with 'TAOS': [%s]\n", arg);
|
||||
return -1;
|
||||
}
|
||||
driverName = arg;
|
||||
} else {
|
||||
fprintf(stderr, "unknown argument: [%s]\n", arg);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!driverName) {
|
||||
fprintf(stderr, "TaosDriverName not specified\n");
|
||||
return -1;
|
||||
}
|
||||
BOOL ok = 1;
|
||||
DWORD usageCount = 1;
|
||||
do {
|
||||
ok = SQLRemoveDriver(driverName, 0, &usageCount);
|
||||
if (!ok) {
|
||||
fprintf(stderr, "failed to remove driver [%s]\n", driverName);
|
||||
return -1;
|
||||
}
|
||||
if (!forceful) {
|
||||
fprintf(stderr, "UsageCount for ODBC driver [%s] is now: [%d]\n", driverName, usageCount);
|
||||
return argc;
|
||||
}
|
||||
} while (usageCount > 0);
|
||||
fprintf(stderr, "ODBC driver [%s] is now fully uninstalled\n", driverName);
|
||||
return argc;
|
||||
}
|
||||
|
|
@ -24,9 +24,9 @@ extern "C" {
|
|||
#include <stdbool.h>
|
||||
|
||||
#ifdef TAOS_ERROR_C
|
||||
#define TAOS_DEFINE_ERROR(name, mod, code, msg) {.val = (0x80000000 | ((mod)<<16) | (code)), .str=(msg)},
|
||||
#define TAOS_DEFINE_ERROR(name, mod, code, msg) {.val = (int32_t)((0x80000000 | ((mod)<<16) | (code))), .str=(msg)},
|
||||
#else
|
||||
#define TAOS_DEFINE_ERROR(name, mod, code, msg) static const int32_t name = (0x80000000 | ((mod)<<16) | (code));
|
||||
#define TAOS_DEFINE_ERROR(name, mod, code, msg) static const int32_t name = (int32_t)((0x80000000 | ((mod)<<16) | (code)));
|
||||
#endif
|
||||
|
||||
#define TAOS_SYSTEM_ERROR(code) (0x80ff0000 | (code))
|
||||
|
@ -107,6 +107,7 @@ TAOS_DEFINE_ERROR(TSDB_CODE_TSC_CONN_KILLED, 0, 0x0215, "Connection
|
|||
TAOS_DEFINE_ERROR(TSDB_CODE_TSC_SQL_SYNTAX_ERROR, 0, 0x0216, "Syntax error in SQL")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TSC_DB_NOT_SELECTED, 0, 0x0217, "Database not specified or available")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TSC_INVALID_TABLE_NAME, 0, 0x0218, "Table does not exist")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_TSC_EXCEED_SQL_LIMIT, 0, 0x0219, "SQL statement too long, check maxSQLLength config")
|
||||
|
||||
// mnode
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_MSG_NOT_PROCESSED, 0, 0x0300, "Message not processed")
|
||||
|
@ -365,20 +366,28 @@ TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_VALUE_NULL, 0, 0x11A5, "value not
|
|||
TAOS_DEFINE_ERROR(TSDB_CODE_HTTP_OP_VALUE_TYPE, 0, 0x11A6, "value type should be boolean, number or string")
|
||||
|
||||
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OOM, 0, 0x2101, "out of memory")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OOM, 0, 0x2100, "out of memory")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_CHAR_NOT_NUM, 0, 0x2101, "convertion not a valid literal input")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_UNDEF, 0, 0x2102, "convertion undefined")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC, 0, 0x2103, "convertion truncated")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_NOT_SUPPORT, 0, 0x2104, "convertion not supported")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OUT_OF_RANGE, 0, 0x2105, "out of range")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NOT_SUPPORT, 0, 0x2106, "not supported yet")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_HANDLE, 0, 0x2107, "invalid handle")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_RESULT, 0, 0x2108, "no result set")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_FIELDS, 0, 0x2109, "no fields returned")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_CURSOR, 0, 0x2110, "invalid cursor")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_STATEMENT_NOT_READY, 0, 0x2111, "statement not ready")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONNECTION_BUSY, 0, 0x2112, "connection still busy")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_CONNSTR, 0, 0x2113, "bad connection string")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_ARG, 0, 0x2114, "bad argument")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC_FRAC, 0, 0x2103, "convertion fractional truncated")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_TRUNC, 0, 0x2104, "convertion truncated")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_NOT_SUPPORT, 0, 0x2105, "convertion not supported")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_OOR, 0, 0x2106, "convertion numeric value out of range")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_OUT_OF_RANGE, 0, 0x2107, "out of range")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NOT_SUPPORT, 0, 0x2108, "not supported yet")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_HANDLE, 0, 0x2109, "invalid handle")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_RESULT, 0, 0x210a, "no result set")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_NO_FIELDS, 0, 0x210b, "no fields returned")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_INVALID_CURSOR, 0, 0x210c, "invalid cursor")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_STATEMENT_NOT_READY, 0, 0x210d, "statement not ready")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONNECTION_BUSY, 0, 0x210e, "connection still busy")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_CONNSTR, 0, 0x210f, "bad connection string")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_BAD_ARG, 0, 0x2110, "bad argument")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_NOT_VALID_TS, 0, 0x2111, "not a valid timestamp")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_SRC_TOO_LARGE, 0, 0x2112, "src too large")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_SRC_BAD_SEQ, 0, 0x2113, "src bad sequence")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_SRC_INCOMPLETE, 0, 0x2114, "src incomplete")
|
||||
TAOS_DEFINE_ERROR(TSDB_CODE_ODBC_CONV_SRC_GENERAL, 0, 0x2115, "src general")
|
||||
|
||||
|
||||
#ifdef TAOS_ERROR_C
|
||||
|
|
|
@ -38,14 +38,14 @@ int32_t taosGetTimestampSec();
|
|||
static FORCE_INLINE int64_t taosGetTimestampMs() {
|
||||
struct timeval systemTime;
|
||||
gettimeofday(&systemTime, NULL);
|
||||
return (int64_t)systemTime.tv_sec * 1000L + (uint64_t)systemTime.tv_usec / 1000;
|
||||
return (int64_t)systemTime.tv_sec * 1000L + (int64_t)systemTime.tv_usec / 1000;
|
||||
}
|
||||
|
||||
//@return timestamp in microsecond
|
||||
static FORCE_INLINE int64_t taosGetTimestampUs() {
|
||||
struct timeval systemTime;
|
||||
gettimeofday(&systemTime, NULL);
|
||||
return (int64_t)systemTime.tv_sec * 1000000L + (uint64_t)systemTime.tv_usec;
|
||||
return (int64_t)systemTime.tv_sec * 1000000L + (int64_t)systemTime.tv_usec;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "msvcProcess.h"
|
||||
#include "msvcDirect.h"
|
||||
#include "msvcFcntl.h"
|
||||
#include "msvcLibgen.h"
|
||||
#include "msvcStdio.h"
|
||||
#include "sys/msvcStat.h"
|
||||
#include "sys/msvcTypes.h"
|
||||
|
|
|
@ -31,7 +31,10 @@
|
|||
#pragma comment(lib, "Mswsock.lib ")
|
||||
#endif
|
||||
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4091)
|
||||
#include <DbgHelp.h>
|
||||
#pragma warning(pop)
|
||||
|
||||
static void taosGetSystemTimezone() {
|
||||
// get and set default timezone
|
||||
|
|
Loading…
Reference in New Issue