diff --git a/.gitmodules b/.gitmodules index e119fbc..0c25d15 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,4 @@ [submodule "lib/clickhouse-cpp"] path = lib/clickhouse-cpp - url = https://github.com/aiwhj/clickhouse-cpp.git + url = https://github.com/amuluowin/clickhouse-cpp.git + branch = master diff --git a/.travis.yml b/.travis.yml index db26a99..e9a065d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,6 +7,9 @@ compiler: os: - linux +env: + - REPORT_EXIT_STATUS=1 NO_INTERACTION=1 + services: - docker @@ -16,6 +19,7 @@ addons: - clickhouse php: + - 5.4 - 5.5 - 5.6 - 7.0 diff --git a/README.md b/README.md index d318c98..a426d1a 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ PHP client for [Yandex ClickHouse](https://clickhouse.yandex/),Based on [Click **Multidimensional arrays are not supported at this time** * Date * DateTime +* Decimal32, Decimal64, Decimal128 * Enum8, Enum16 * FixedString(N) * Float32, Float64 @@ -23,7 +24,7 @@ PHP client for [Yandex ClickHouse](https://clickhouse.yandex/),Based on [Click * UInt8, UInt16, UInt32, UInt64, Int8, Int16, Int32, Int64 ## Supported PHP version -PHP 5.5+ +PHP 5.4+ ## Performance ![image](https://github.com/SeasX/SeasClick/raw/master/tests/bench_mark/bench_mark.png) @@ -33,8 +34,6 @@ This performance test [demo](https://github.com/SeasX/SeasClick/blob/master/test ## Install ```ssh git clone https://github.com/SeasX/SeasClick.git -git submodule init -git submodule update cd SeasClick phpize ./configure @@ -86,7 +85,7 @@ function testArray($client, $deleteTable = false) { } } ``` -#### [More examples](https://github.com/SeasX/SeasClick/tests/test.php) +#### [More examples](https://github.com/SeasX/SeasClick/blob/master/tests/test.php) ## Support SeasX Group diff --git a/SeasClick.cpp b/SeasClick.cpp index 85aa911..1c73ef2 100644 --- a/SeasClick.cpp +++ b/SeasClick.cpp @@ -19,7 +19,8 @@ #include "config.h" #endif -extern "C" { +extern "C" +{ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" @@ -41,25 +42,33 @@ using namespace clickhouse; using namespace std; zend_class_entry *SeasClick_ce; -map clientMap; +map clientMap; +map blockQueryMap; #ifdef COMPILE_DL_SEASCLICK -extern "C" { -ZEND_GET_MODULE(SeasClick) +extern "C" +{ + ZEND_GET_MODULE(SeasClick) } #endif PHP_FUNCTION(SeasClick_version) { - SC_RETURN_STRINGL(PHP_SEASCLICK_VERSION, strlen(PHP_SEASCLICK_VERSION)); + SC_RETURN_STRINGL(PHP_SEASCLICK_VERSION, strlen(PHP_SEASCLICK_VERSION)); } static PHP_METHOD(SEASCLICK_RES_NAME, __construct); static PHP_METHOD(SEASCLICK_RES_NAME, __destruct); static PHP_METHOD(SEASCLICK_RES_NAME, select); static PHP_METHOD(SEASCLICK_RES_NAME, insert); +static PHP_METHOD(SEASCLICK_RES_NAME, insertStart); +static PHP_METHOD(SEASCLICK_RES_NAME, insertData); +static PHP_METHOD(SEASCLICK_RES_NAME, insertEnd); static PHP_METHOD(SEASCLICK_RES_NAME, execute); +ZEND_BEGIN_ARG_INFO_EX(SeasCilck_void, 0, 0, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(SeasCilck_construct, 0, 0, 1) ZEND_ARG_INFO(0, connectParames) ZEND_END_ARG_INFO() @@ -75,27 +84,38 @@ ZEND_ARG_INFO(0, columns) ZEND_ARG_INFO(0, values) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(SeasCilck_insertStart, 0, 0, 2) +ZEND_ARG_INFO(0, table) +ZEND_ARG_INFO(0, columns) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(SeasCilck_insertData, 0, 0, 1) +ZEND_ARG_INFO(0, values) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_INFO_EX(SeasCilck_execute, 0, 0, 2) ZEND_ARG_INFO(0, sql) ZEND_ARG_INFO(0, params) ZEND_END_ARG_INFO() /* {{{ SeasClick_functions[] */ -const zend_function_entry SeasClick_functions[] = { - PHP_FE(SeasClick_version, NULL) - PHP_FE_END -}; +const zend_function_entry SeasClick_functions[] = + { + PHP_FE(SeasClick_version, SeasCilck_void) + PHP_FE_END}; /* }}} */ const zend_function_entry SeasClick_methods[] = -{ - PHP_ME(SEASCLICK_RES_NAME, __construct, SeasCilck_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) - PHP_ME(SEASCLICK_RES_NAME, __destruct, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR) - PHP_ME(SEASCLICK_RES_NAME, select, SeasCilck_select, ZEND_ACC_PUBLIC) - PHP_ME(SEASCLICK_RES_NAME, insert, SeasCilck_insert, ZEND_ACC_PUBLIC) - PHP_ME(SEASCLICK_RES_NAME, execute, SeasCilck_execute, ZEND_ACC_PUBLIC) - PHP_FE_END -}; + { + PHP_ME(SEASCLICK_RES_NAME, __construct, SeasCilck_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR) + PHP_ME(SEASCLICK_RES_NAME, __destruct, SeasCilck_void, ZEND_ACC_PUBLIC | ZEND_ACC_DTOR) + PHP_ME(SEASCLICK_RES_NAME, select, SeasCilck_select, ZEND_ACC_PUBLIC) + PHP_ME(SEASCLICK_RES_NAME, insert, SeasCilck_insert, ZEND_ACC_PUBLIC) + PHP_ME(SEASCLICK_RES_NAME, insertStart, SeasCilck_insertStart, ZEND_ACC_PUBLIC) + PHP_ME(SEASCLICK_RES_NAME, insertData, SeasCilck_insertData, ZEND_ACC_PUBLIC) + PHP_ME(SEASCLICK_RES_NAME, insertEnd, SeasCilck_void, ZEND_ACC_PUBLIC) + PHP_ME(SEASCLICK_RES_NAME, execute, SeasCilck_execute, ZEND_ACC_PUBLIC) + PHP_FE_END}; /* {{{ PHP_MINIT_FUNCTION */ @@ -115,8 +135,8 @@ PHP_MINIT_FUNCTION(SeasClick) zend_declare_property_null(SeasClick_ce, "passwd", strlen("passwd"), ZEND_ACC_PROTECTED TSRMLS_CC); zend_declare_property_bool(SeasClick_ce, "compression", strlen("compression"), false, ZEND_ACC_PROTECTED TSRMLS_CC); - SeasClick_ce->ce_flags = ZEND_ACC_IMPLICIT_PUBLIC; - return SUCCESS; + SeasClick_ce->ce_flags |= ZEND_ACC_FINAL; + return SUCCESS; } /* }}} */ @@ -124,7 +144,7 @@ PHP_MINIT_FUNCTION(SeasClick) */ PHP_MSHUTDOWN_FUNCTION(SeasClick) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -132,7 +152,7 @@ PHP_MSHUTDOWN_FUNCTION(SeasClick) */ PHP_RINIT_FUNCTION(SeasClick) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -140,7 +160,7 @@ PHP_RINIT_FUNCTION(SeasClick) */ PHP_RSHUTDOWN_FUNCTION(SeasClick) { - return SUCCESS; + return SUCCESS; } /* }}} */ @@ -148,30 +168,35 @@ PHP_RSHUTDOWN_FUNCTION(SeasClick) */ PHP_MINFO_FUNCTION(SeasClick) { - php_info_print_table_start(); - php_info_print_table_header(2, "SeasClick support", "enabled"); + php_info_print_table_start(); + php_info_print_table_header(2, "SeasClick support", "enabled"); php_info_print_table_row(2, "Version", PHP_SEASCLICK_VERSION); php_info_print_table_row(2, "Author", "SeasX Group[email: ahhhh.wang@gmail.com]"); - php_info_print_table_end(); +#ifdef USE_SWOOLE + php_info_print_table_row(2, "Swoole", "enabled"); +#else + php_info_print_table_row(2, "Swoole", "disable"); +#endif + php_info_print_table_end(); - DISPLAY_INI_ENTRIES(); + DISPLAY_INI_ENTRIES(); } /* }}} */ /* {{{ SeasClick_module_entry */ -zend_module_entry SeasClick_module_entry = { - STANDARD_MODULE_HEADER, - SEASCLICK_RES_NAME, - SeasClick_functions, - PHP_MINIT(SeasClick), - PHP_MSHUTDOWN(SeasClick), - PHP_RINIT(SeasClick), - PHP_RSHUTDOWN(SeasClick), - PHP_MINFO(SeasClick), - PHP_SEASCLICK_VERSION, - STANDARD_MODULE_PROPERTIES -}; +zend_module_entry SeasClick_module_entry = + { + STANDARD_MODULE_HEADER, + SEASCLICK_RES_NAME, + SeasClick_functions, + PHP_MINIT(SeasClick), + PHP_MSHUTDOWN(SeasClick), + PHP_RINIT(SeasClick), + PHP_RSHUTDOWN(SeasClick), + PHP_MINFO(SeasClick), + PHP_SEASCLICK_VERSION, + STANDARD_MODULE_PROPERTIES}; /* }}} */ /* {{{ proto object __construct(array connectParames) @@ -181,14 +206,15 @@ PHP_METHOD(SEASCLICK_RES_NAME, __construct) zval *connectParames; #ifndef FAST_ZPP - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &connectParames) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &connectParames) == FAILURE) + { return; } #else #undef IS_UNDEF #define IS_UNDEF Z_EXPECTED_LONG ZEND_PARSE_PARAMETERS_START(1, 1) - Z_PARAM_ARRAY(connectParames) + Z_PARAM_ARRAY(connectParames) ZEND_PARSE_PARAMETERS_END(); #undef IS_UNDEF #define IS_UNDEF 0 @@ -202,62 +228,66 @@ PHP_METHOD(SEASCLICK_RES_NAME, __construct) if (php_array_get_value(_ht, "host", value)) { convert_to_string(value); - zend_update_property_string(SeasClick_ce, this_obj, "host", sizeof("host") - 1, Z_STRVAL_P(value) TSRMLS_CC); + zend_update_property_string(SeasClick_ce, SC_OBJ_P(this_obj), "host", sizeof("host") - 1, Z_STRVAL_P(value) TSRMLS_CC); } if (php_array_get_value(_ht, "port", value)) { convert_to_long(value); - zend_update_property_long(SeasClick_ce, this_obj, "port", sizeof("port") - 1, Z_LVAL_P(value) TSRMLS_CC); + zend_update_property_long(SeasClick_ce, SC_OBJ_P(this_obj), "port", sizeof("port") - 1, Z_LVAL_P(value) TSRMLS_CC); } if (php_array_get_value(_ht, "compression", value)) { convert_to_boolean(value); - zend_update_property_bool(SeasClick_ce, this_obj, "compression", sizeof("compression") - 1, Z_LVAL_P(value) TSRMLS_CC); + zend_update_property_bool(SeasClick_ce, SC_OBJ_P(this_obj), "compression", sizeof("compression") - 1, Z_LVAL_P(value) TSRMLS_CC); } - zval *host = sc_zend_read_property(SeasClick_ce, this_obj, "host", sizeof("host") - 1, 0); - zval *port = sc_zend_read_property(SeasClick_ce, this_obj, "port", sizeof("port") - 1, 0); - zval *compression = sc_zend_read_property(SeasClick_ce, this_obj, "compression", sizeof("compression") - 1, 0); + zval *host = sc_zend_read_property(SeasClick_ce, SC_OBJ_P(this_obj), "host", sizeof("host") - 1, 0); + zval *port = sc_zend_read_property(SeasClick_ce, SC_OBJ_P(this_obj), "port", sizeof("port") - 1, 0); + zval *compression = sc_zend_read_property(SeasClick_ce, SC_OBJ_P(this_obj), "compression", sizeof("compression") - 1, 0); ClientOptions Options = ClientOptions() .SetHost(Z_STRVAL_P(host)) .SetPort(Z_LVAL_P(port)) - .SetPingBeforeQuery(false); - if (Z_TYPE_P(compression) == IS_TRUE) { + .SetPingBeforeQuery(false) + .TcpKeepAlive(true); + if (Z_TYPE_P(compression) == IS_TRUE) + { Options = Options.SetCompressionMethod(CompressionMethod::LZ4); } if (php_array_get_value(_ht, "database", value)) { convert_to_string(value); - zend_update_property_string(SeasClick_ce, this_obj, "database", sizeof("database") - 1, Z_STRVAL_P(value) TSRMLS_CC); + zend_update_property_string(SeasClick_ce, SC_OBJ_P(this_obj), "database", sizeof("database") - 1, Z_STRVAL_P(value) TSRMLS_CC); Options = Options.SetDefaultDatabase(Z_STRVAL_P(value)); } if (php_array_get_value(_ht, "user", value)) { convert_to_string(value); - zend_update_property_string(SeasClick_ce, this_obj, "user", sizeof("user") - 1, Z_STRVAL_P(value) TSRMLS_CC); + zend_update_property_string(SeasClick_ce, SC_OBJ_P(this_obj), "user", sizeof("user") - 1, Z_STRVAL_P(value) TSRMLS_CC); Options = Options.SetUser(Z_STRVAL_P(value)); } if (php_array_get_value(_ht, "passwd", value)) { convert_to_string(value); - zend_update_property_string(SeasClick_ce, this_obj, "passwd", sizeof("passwd") - 1, Z_STRVAL_P(value) TSRMLS_CC); + zend_update_property_string(SeasClick_ce, SC_OBJ_P(this_obj), "passwd", sizeof("passwd") - 1, Z_STRVAL_P(value) TSRMLS_CC); Options = Options.SetPassword(Z_STRVAL_P(value)); } - try { + try + { Client *client = new Client(Options); int key = Z_OBJ_HANDLE(*this_obj); - clientMap.insert(std::pair(key, client)); - - } catch (const std::exception& e) { - zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + clientMap.insert(std::pair(key, client)); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); } RETURN_TRUE; @@ -280,9 +310,12 @@ void getInsertSql(string *sql, char *table_name, zval *columns) SC_HASHTABLE_FOREACH_START2(columns_ht, key, keylen, keytype, pzval) { convert_to_string(pzval); - if (index >= (count - 1)) { + if (index >= (count - 1)) + { fields_section << (string)Z_STRVAL_P(pzval); - } else { + } + else + { fields_section << (string)Z_STRVAL_P(pzval) << ","; } index++; @@ -297,27 +330,31 @@ PHP_METHOD(SEASCLICK_RES_NAME, select) { char *sql = NULL; size_t l_sql = 0; - zval* params = NULL; + zval *params = NULL; #ifndef FAST_ZPP - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &sql, &l_sql, ¶ms) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &sql, &l_sql, ¶ms) == FAILURE) + { return; } #else #undef IS_UNDEF #define IS_UNDEF Z_EXPECTED_LONG ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(sql, l_sql) - Z_PARAM_OPTIONAL - Z_PARAM_ARRAY(params) + Z_PARAM_STRING(sql, l_sql) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY(params) ZEND_PARSE_PARAMETERS_END(); #undef IS_UNDEF #define IS_UNDEF 0 #endif - try { + try + { string sql_s = (string)sql; - if (ZEND_NUM_ARGS() > 1 && params != NULL) { - if (Z_TYPE_P(params) != IS_ARRAY) { + if (ZEND_NUM_ARGS() > 1 && params != NULL) + { + if (Z_TYPE_P(params) != IS_ARRAY) + { throw std::runtime_error("The second argument to the select function must be an array"); } @@ -340,23 +377,24 @@ PHP_METHOD(SEASCLICK_RES_NAME, select) array_init(return_value); - client->Select(sql_s, [return_value](const Block& block) + client->Select(sql_s, [return_value](const Block &block) { + zval *return_tmp; + for (size_t row = 0; row < block.GetRowCount(); ++row) { - zval *return_tmp; - for (size_t row = 0; row < block.GetRowCount(); ++row) { - SC_MAKE_STD_ZVAL(return_tmp); - array_init(return_tmp); - for (size_t column = 0; column < block.GetColumnCount(); ++column) { - string column_name = block.GetColumnName(column); - convertToZval(return_tmp, block[column], row, column_name, 0); - } - add_next_index_zval(return_value, return_tmp); + SC_MAKE_STD_ZVAL(return_tmp); + array_init(return_tmp); + for (size_t column = 0; column < block.GetColumnCount(); ++column) + { + string column_name = block.GetColumnName(column); + convertToZval(return_tmp, block[column], row, column_name, 0); } + add_next_index_zval(return_value, return_tmp); } - ); - - } catch (const std::exception& e) { - zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + }); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); } } /* }}} */ @@ -373,22 +411,24 @@ PHP_METHOD(SEASCLICK_RES_NAME, insert) string sql; #ifndef FAST_ZPP - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szz", &table, &l_table, &columns, &values) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "szz", &table, &l_table, &columns, &values) == FAILURE) + { return; } #else #undef IS_UNDEF #define IS_UNDEF Z_EXPECTED_LONG ZEND_PARSE_PARAMETERS_START(3, 3) - Z_PARAM_STRING(table, l_table) - Z_PARAM_ARRAY(columns) - Z_PARAM_ARRAY(values) + Z_PARAM_STRING(table, l_table) + Z_PARAM_ARRAY(columns) + Z_PARAM_ARRAY(values) ZEND_PARSE_PARAMETERS_END(); #undef IS_UNDEF #define IS_UNDEF 0 #endif - try { + try + { HashTable *columns_ht = Z_ARRVAL_P(columns); HashTable *values_ht = Z_ARRVAL_P(values); size_t columns_count = zend_hash_num_elements(columns_ht); @@ -404,18 +444,20 @@ PHP_METHOD(SEASCLICK_RES_NAME, insert) int keytype; zval *return_tmp; - for(size_t i = 0; i < columns_count; i++) + for (size_t i = 0; i < columns_count; i++) { SC_MAKE_STD_ZVAL(return_tmp); array_init(return_tmp); SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, pzval) { - if (Z_TYPE_P(pzval) != IS_ARRAY) { + if (Z_TYPE_P(pzval) != IS_ARRAY) + { throw std::runtime_error("The insert function needs to pass in a two-dimensional array"); } fzval = sc_zend_hash_index_find(Z_ARRVAL_P(pzval), i); - if (NULL == fzval) { + if (NULL == fzval) + { throw std::runtime_error("The number of parameters inserted per line is inconsistent"); } sc_zval_add_ref(fzval); @@ -427,16 +469,15 @@ PHP_METHOD(SEASCLICK_RES_NAME, insert) } getInsertSql(&sql, table, columns); - Block blockQuery; int key = Z_OBJ_HANDLE(*getThis()); Client *client = clientMap.at(key); + Block blockQuery; + + client->InsertQuery(sql, [&blockQuery](const Block &block) { + blockQuery = block; + }); - client->InsertQuery(sql, [&blockQuery](const Block& block) { - blockQuery = block; - } - ); - Block blockInsert; size_t index = 0; @@ -449,9 +490,182 @@ PHP_METHOD(SEASCLICK_RES_NAME, insert) client->InsertData(blockInsert); sc_zval_ptr_dtor(&return_should); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto array insertStart(string table, array columns) + */ +PHP_METHOD(SEASCLICK_RES_NAME, insertStart) +{ + char *table = NULL; + size_t l_table = 0; + zval *columns; + + string sql; + +#ifndef FAST_ZPP + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz", &table, &l_table, &columns) == FAILURE) + { + return; + } +#else +#undef IS_UNDEF +#define IS_UNDEF Z_EXPECTED_LONG + ZEND_PARSE_PARAMETERS_START(2, 2) + Z_PARAM_STRING(table, l_table) + Z_PARAM_ARRAY(columns) + ZEND_PARSE_PARAMETERS_END(); +#undef IS_UNDEF +#define IS_UNDEF 0 +#endif + + try + { + HashTable *columns_ht = Z_ARRVAL_P(columns); + size_t columns_count = zend_hash_num_elements(columns_ht); + + getInsertSql(&sql, table, columns); + + int key = Z_OBJ_HANDLE(*getThis()); + + if (blockQueryMap.count(key)) + { + throw std::runtime_error("The insert operation is now in progress"); + } + Client *client = clientMap.at(key); + + Block blockQuery; + client->InsertQuery(sql, [&blockQuery](const Block &block) { + blockQuery = block; + }); + + blockQueryMap.insert(std::pair(key, blockQuery)); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto array insertData(array values) + */ +PHP_METHOD(SEASCLICK_RES_NAME, insertData) +{ + zval *values; + +#ifndef FAST_ZPP + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &values) == FAILURE) + { + return; + } +#else +#undef IS_UNDEF +#define IS_UNDEF Z_EXPECTED_LONG + ZEND_PARSE_PARAMETERS_START(1, 1) + Z_PARAM_ARRAY(values) + ZEND_PARSE_PARAMETERS_END(); +#undef IS_UNDEF +#define IS_UNDEF 0 +#endif + + try + { + HashTable *values_ht = Z_ARRVAL_P(values); + zval *tmp = zend_hash_get_current_data(values_ht); + if (tmp == NULL) + { + RETURN_FALSE; + } + size_t count = zend_hash_num_elements(Z_ARRVAL_P(tmp)); + + int key = Z_OBJ_HANDLE(*getThis()); + if (blockQueryMap.count(key) == 0) + { + throw std::runtime_error("The insert operation is not start"); + } + Client *client = clientMap.at(key); + Block blockQuery = blockQueryMap.at(key); + + zval *return_should; + SC_MAKE_STD_ZVAL(return_should); + array_init(return_should); + + zval *fzval, *pzval; + char *str_key; + uint32_t str_keylen; + int keytype; + + zval *return_tmp; + for (size_t i = 0; i < count; i++) + { + SC_MAKE_STD_ZVAL(return_tmp); + array_init(return_tmp); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, pzval) + { + if (Z_TYPE_P(pzval) != IS_ARRAY) + { + throw std::runtime_error("The insert function needs to pass in a two-dimensional array"); + } + fzval = sc_zend_hash_index_find(Z_ARRVAL_P(pzval), i); + if (NULL == fzval) + { + throw std::runtime_error("The number of parameters inserted per line is inconsistent"); + } + sc_zval_add_ref(fzval); + add_next_index_zval(return_tmp, fzval); + } + SC_HASHTABLE_FOREACH_END(); + + add_next_index_zval(return_should, return_tmp); + } + + Block blockInsert; + size_t index = 0; + SC_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(return_should), str_key, str_keylen, keytype, pzval) + { + zvalToBlock(blockInsert, blockQuery, index, pzval); + index++; + } + SC_HASHTABLE_FOREACH_END(); + + client->InsertBlock(blockInsert); + sc_zval_ptr_dtor(&return_should); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + } + RETURN_TRUE; +} +/* }}} */ - } catch (const std::exception& e) { - zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); +/* {{{ proto void insertEnd() + */ +PHP_METHOD(SEASCLICK_RES_NAME, insertEnd) +{ + try + { + int key = Z_OBJ_HANDLE(*getThis()); + if (blockQueryMap.count(key) == 0) + { + throw std::runtime_error("The insert operation is not start"); + } + Client *client = clientMap.at(key); + client->InsertEnd(); + blockQueryMap.erase(key); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); } RETURN_TRUE; } @@ -463,28 +677,32 @@ PHP_METHOD(SEASCLICK_RES_NAME, execute) { char *sql = NULL; size_t l_sql = 0; - zval* params = NULL; + zval *params = NULL; #ifndef FAST_ZPP - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &sql, &l_sql, ¶ms) == FAILURE) { + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|z", &sql, &l_sql, ¶ms) == FAILURE) + { return; } #else #undef IS_UNDEF #define IS_UNDEF Z_EXPECTED_LONG ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(sql, l_sql) - Z_PARAM_OPTIONAL - Z_PARAM_ARRAY(params) + Z_PARAM_STRING(sql, l_sql) + Z_PARAM_OPTIONAL + Z_PARAM_ARRAY(params) ZEND_PARSE_PARAMETERS_END(); #undef IS_UNDEF #define IS_UNDEF 0 #endif - try { + try + { string sql_s = (string)sql; - if (ZEND_NUM_ARGS() > 1 && params != NULL) { - if (Z_TYPE_P(params) != IS_ARRAY) { + if (ZEND_NUM_ARGS() > 1 && params != NULL) + { + if (Z_TYPE_P(params) != IS_ARRAY) + { throw std::runtime_error("The second argument to the select function must be an array"); } @@ -505,26 +723,29 @@ PHP_METHOD(SEASCLICK_RES_NAME, execute) int key = Z_OBJ_HANDLE(*getThis()); Client *client = clientMap.at(key); client->Execute(sql_s); - - } catch (const std::exception& e) { - zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); } RETURN_TRUE; } /* }}} */ -/* {{{ proto array __destruct() +/* {{{ proto void __destruct() */ PHP_METHOD(SEASCLICK_RES_NAME, __destruct) { - try { + try + { int key = Z_OBJ_HANDLE(*getThis()); Client *client = clientMap.at(key); delete client; clientMap.erase(key); - - } catch (const std::exception& e) { - zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); + } + catch (const std::exception &e) + { + sc_zend_throw_exception(NULL, e.what(), 0 TSRMLS_CC); } RETURN_TRUE; } diff --git a/config.m4 b/config.m4 index e6d3402..8f47b1c 100644 --- a/config.m4 +++ b/config.m4 @@ -16,6 +16,8 @@ dnl Otherwise use enable: PHP_ARG_ENABLE(SeasClick, whether to enable SeasClick support, Make sure that the comment is aligned: [ --enable-SeasClick Enable SeasClick support]) +PHP_ARG_ENABLE(swoole, enable swoole support, +[ --enable-swoole Use swoole], yes, no) if test "$PHP_SEASCLICK" != "no"; then dnl Write more examples of tests here... @@ -58,10 +60,17 @@ if test "$PHP_SEASCLICK" != "no"; then dnl ]) dnl dnl PHP_SUBST(SEASCLICK_SHARED_LIBADD) + + if test "$PHP_SWOOLE" = "yes"; then + if test -e $(/usr/bin/php-config --include-dir)/ext/swoole/include/swoole_socket_hook.h; then + AC_DEFINE(USE_SWOOLE, 1, [enable swoole support]) + CXXFLAGS="$CXXFLAGS -DUSE_SWOOLE" + fi + fi PHP_REQUIRE_CXX() PHP_SUBST(SEASCLICK_SHARED_LIBADD) PHP_ADD_LIBRARY(stdc++, 1, SEASCLICK_SHARED_LIBADD) - CXXFLAGS="$CXXFLAGS -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=c++11" + CXXFLAGS="$CXXFLAGS -Wall -Wno-unused-function -Wno-deprecated -Wno-deprecated-declarations -std=gnu++17" SeasClick_source_file="SeasClick.cpp \ typesToPhp.cpp \ lib/clickhouse-cpp/clickhouse/base/coded.cpp \ @@ -70,31 +79,47 @@ if test "$PHP_SEASCLICK" != "no"; then lib/clickhouse-cpp/clickhouse/base/output.cpp \ lib/clickhouse-cpp/clickhouse/base/platform.cpp \ lib/clickhouse-cpp/clickhouse/base/socket.cpp \ + lib/clickhouse-cpp/clickhouse/columns/array.cpp \ lib/clickhouse-cpp/clickhouse/columns/date.cpp \ + lib/clickhouse-cpp/clickhouse/columns/decimal.cpp \ lib/clickhouse-cpp/clickhouse/columns/enum.cpp \ lib/clickhouse-cpp/clickhouse/columns/factory.cpp \ + lib/clickhouse-cpp/clickhouse/columns/ip4.cpp \ + lib/clickhouse-cpp/clickhouse/columns/ip6.cpp \ + lib/clickhouse-cpp/clickhouse/columns/lowcardinality.cpp \ lib/clickhouse-cpp/clickhouse/columns/nullable.cpp \ lib/clickhouse-cpp/clickhouse/columns/numeric.cpp \ lib/clickhouse-cpp/clickhouse/columns/string.cpp \ lib/clickhouse-cpp/clickhouse/columns/tuple.cpp \ lib/clickhouse-cpp/clickhouse/columns/uuid.cpp \ + lib/clickhouse-cpp/clickhouse/columns/itemview.cpp \ + lib/clickhouse-cpp/clickhouse/types/type_parser.cpp \ lib/clickhouse-cpp/clickhouse/types/types.cpp \ + lib/clickhouse-cpp/contrib/cityhash/city.cc \ lib/clickhouse-cpp/contrib/lz4/lz4.c \ lib/clickhouse-cpp/contrib/lz4/lz4hc.c \ lib/clickhouse-cpp/contrib/gtest/gtest-all.cc \ + lib/clickhouse-cpp/clickhouse/block.cpp \ lib/clickhouse-cpp/clickhouse/client.cpp \ lib/clickhouse-cpp/clickhouse/query.cpp" SeasClick_header_file="lib/clickhouse-cpp/contrib" - - PHP_ADD_INCLUDE([$SeasClick_header_file]) + + THIS_DIR=`dirname $0` + PHP_ADD_INCLUDE($THIS_DIR/lib/clickhouse-cpp/contrib) PHP_NEW_EXTENSION(SeasClick, $SeasClick_source_file, $ext_shared,,-DZEND_ENABLE_STATIC_TSRMLS_CACHE=1) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/contrib) PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/contrib/cityhash) PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/contrib/gtest) PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/contrib/lz4) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/clickhouse) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/clickhouse/base) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/clickhouse/types) + PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp/clickhouse/columns) PHP_ADD_BUILD_DIR($ext_builddir/lib/clickhouse-cpp) fi diff --git a/config.w32 b/config.w32.without similarity index 100% rename from config.w32 rename to config.w32.without diff --git a/lib/clickhouse-cpp b/lib/clickhouse-cpp index bab28bc..cce2087 160000 --- a/lib/clickhouse-cpp +++ b/lib/clickhouse-cpp @@ -1 +1 @@ -Subproject commit bab28bcb5a509d80b8e2e0c7e89512446283dde5 +Subproject commit cce20871c7b391b35c5538081d10b0a7c239e4b4 diff --git a/package.xml b/package.xml new file mode 100644 index 0000000..c4756ab --- /dev/null +++ b/package.xml @@ -0,0 +1,170 @@ + + + SeasClick + pecl.php.net + An Yandex ClickHouse client driven extension for PHP. + + PHP client for Yandex ClickHouse,Based on ClickHouse C++ client. + + + Chitao Gao + neeke + neeke@php.net + yes + + 2019-03-28 + + + 0.1.0 + 0.1.0 + + + stable + stable + + PHP3.01 + + - First version for pecl.net + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5.4.0 + + + 1.4.0 + + + + SeasClick + + + + + diff --git a/php7_wrapper.h b/php7_wrapper.h index a9e3acf..8489031 100644 --- a/php7_wrapper.h +++ b/php7_wrapper.h @@ -15,8 +15,28 @@ | Author: SeasX Group | +----------------------------------------------------------------------+ */ + +// PHP7.4 + +#if !defined(ZEND_ACC_IMPLICIT_PUBLIC) +# define ZEND_ACC_IMPLICIT_PUBLIC ZEND_ACC_PUBLIC +#endif + +#ifndef ZEND_ACC_CTOR +#define ZEND_ACC_CTOR 0 +#endif +#ifndef ZEND_ACC_DTOR +#define ZEND_ACC_DTOR 0 +#endif + // PHP7+ #if PHP_MAJOR_VERSION < 7 + +#if PHP_VERSION_ID < 50500 +#define sc_zend_throw_exception(a, b, c) zend_throw_exception(a, (char *)b, c) +#else +#define sc_zend_throw_exception zend_throw_exception +#endif + #define IS_TRUE 1 #define SC_MAKE_STD_ZVAL(p) MAKE_STD_ZVAL(p) #define SC_RETURN_STRINGL(k, l) RETURN_STRINGL(k, l, 1) @@ -78,7 +98,7 @@ static inline zval *sc_zend_hash_index_find(HashTable *ht, ulong h) #define SC_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, entry)\ zval **tmp = NULL; ulong_t idx;\ for (zend_hash_internal_pointer_reset(ht); \ - (ktype = zend_hash_get_current_key_ex(ht, &k, &klen, &idx, 0, NULL)) != HASH_KEY_NON_EXISTENT; \ + (ktype = zend_hash_get_current_key_ex(ht, &k, &klen, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT; \ zend_hash_move_forward(ht)\ ) { \ if (zend_hash_get_current_data(ht, (void**)&tmp) == FAILURE) {\ @@ -93,6 +113,8 @@ static inline zval *sc_zend_hash_index_find(HashTable *ht, ulong h) #else // PHP5 +#define sc_zend_throw_exception zend_throw_exception + #define sc_zend_hash_find zend_hash_str_find #define sc_zend_hash_index_find zend_hash_index_find #define SC_MAKE_STD_ZVAL(p) zval _stack_zval_##p; p = &(_stack_zval_##p) @@ -104,11 +126,24 @@ static inline zval *sc_zend_hash_index_find(HashTable *ht, ulong h) #define sc_add_assoc_zval_ex add_assoc_zval_ex #define sc_add_assoc_stringl_ex(a, b, c, d, e, f) add_assoc_stringl_ex(a, b, c, d, e) #define sc_add_assoc_null_ex(a, b, c) add_assoc_null_ex(a, b, c) + +// PHP8 +#if PHP_VERSION_ID < 80000 +#define SC_OBJ_P(zobj) zobj static inline zval* sc_zend_read_property(zend_class_entry *class_ptr, zval *obj, const char *s, int len, int silent) { zval rv; return zend_read_property(class_ptr, obj, s, len, silent, &rv); } +#else +#define TSRMLS_CC +#define SC_OBJ_P(zobj) Z_OBJ_P(zobj) +static inline zval* sc_zend_read_property(zend_class_entry *class_ptr, zend_object *obj, const char *s, int len, int silent) +{ + zval rv; + return zend_read_property(class_ptr, obj, s, len, silent, &rv); +} +#endif #define SC_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, _val) zend_string *_foreach_key;\ ZEND_HASH_FOREACH_STR_KEY_VAL(ht, _foreach_key, _val);\ diff --git a/tests/010.phpt b/tests/010.phpt new file mode 100644 index 0000000..c22d914 --- /dev/null +++ b/tests/010.phpt @@ -0,0 +1,77 @@ +--TEST-- +SeasClick testDate +--SKIPIF-- + +--FILE-- + "clickhouse", + "port" => "9000", + "compression" => true +]; + +clientTest($config); + +function clientTest($config) +{ + $deleteTable = true; + $client = new SeasClick($config); + $client->execute("CREATE DATABASE IF NOT EXISTS test"); + + testTuple($client, $deleteTable); +} + +function testTuple($client, $deleteTable = false) { + $client->execute("CREATE TABLE IF NOT EXISTS test.tuple_test (tuple_c Tuple(id UInt64, name String), int_c UInt64, string_c String) ENGINE = Memory"); + + $client->insert("test.tuple_test", [ + 'tuple_c', 'int_c', 'string_c' + ], [ + [[1, 'one'], 1, 'one'], + [[2, 'two'], 2, 'two'], + ]); + $result = $client->select("SELECT {select} FROM {table}", [ + 'select' => 'tuple_c, int_c, string_c', + 'table' => 'test.tuple_test' + ]); + var_dump($result); + + if ($deleteTable) { + $client->execute("DROP TABLE {table}", [ + 'table' => 'test.tuple_test' + ]); + } +} + +?> +--EXPECT-- +array(2) { + [0]=> + array(3) { + ["tuple_c"]=> + array(2) { + [0]=> + int(1) + [1]=> + string(3) "one" + } + ["int_c"]=> + int(1) + ["string_c"]=> + string(3) "one" + } + [1]=> + array(3) { + ["tuple_c"]=> + array(2) { + [0]=> + int(2) + [1]=> + string(3) "two" + } + ["int_c"]=> + int(2) + ["string_c"]=> + string(3) "two" + } +} diff --git a/tests/bench_mark/bench_mark.php b/tests/bench_mark/bench_mark.php index a862743..ed45a8f 100644 --- a/tests/bench_mark/bench_mark.php +++ b/tests/bench_mark/bench_mark.php @@ -176,11 +176,6 @@ function testPhpClickhouse($insertData, $num, $limit) ENGINE = SummingMergeTree(event_date, (site_id, site_key, event_time, event_date), 8192) '); - $a = 100; - $insertData = []; - while ($a--) { - $insertData[] = [time(), 'HASH2', 2345, 12, 9, 3]; - } $db->insert("summing_url_views", $insertData, ['event_time', 'site_key', 'site_id', 'views', 'v_00', 'v_55'] diff --git a/tests/test.php b/tests/test.php index 95fd2f4..bff5c6d 100644 --- a/tests/test.php +++ b/tests/test.php @@ -33,6 +33,7 @@ function clientTest($config) testUUID($client, $deleteTable); testDate($client, $deleteTable); testMulInstance($config, $deleteTable); + testTuple($client, $deleteTable); } function testMulInstance($config, $deleteTable = false) { @@ -54,6 +55,28 @@ function testMulInstance($config, $deleteTable = false) { unset($client4); } +function testTuple($client, $deleteTable = false) { + $client->execute("CREATE TABLE IF NOT EXISTS test.tuple_test (tuple_c Tuple(id UInt64, name String), int_c UInt64, string_c String) ENGINE = Memory"); + + $client->insert("test.tuple_test", [ + 'tuple_c', 'int_c', 'string_c' + ], [ + [[1, 'one'], 1, 'one'], + [[2, 'two'], 2, 'two'], + ]); + $result = $client->select("SELECT {select} FROM {table}", [ + 'select' => 'tuple_c, int_c, string_c', + 'table' => 'test.tuple_test' + ]); + var_dump($result); + + if ($deleteTable) { + $client->execute("DROP TABLE {table}", [ + 'table' => 'test.tuple_test' + ]); + } +} + function testArray($client, $deleteTable = false) { $client->execute("CREATE TABLE IF NOT EXISTS test.array_test (string_c String, array_c Array(Int8), arraynull_c Array(Nullable(String))) ENGINE = Memory"); diff --git a/typesToPhp.cpp b/typesToPhp.cpp index 0c9a0fe..f9342dc 100644 --- a/typesToPhp.cpp +++ b/typesToPhp.cpp @@ -19,7 +19,8 @@ #include "config.h" #endif -extern "C" { +extern "C" +{ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" @@ -46,128 +47,146 @@ ColumnRef createColumn(TypeRef type) { switch (type->GetCode()) { - case Type::Code::UInt64: - { - return std::make_shared(); - } - case Type::Code::UInt8: - { - return std::make_shared(); - } - case Type::Code::UInt16: - { - return std::make_shared(); - } - case Type::Code::UInt32: - { - return std::make_shared(); - } + case Type::Code::UInt64: + { + return std::make_shared(); + } + case Type::Code::UInt8: + { + return std::make_shared(); + } + case Type::Code::UInt16: + { + return std::make_shared(); + } + case Type::Code::IPv4: + { + return std::make_shared(); + } + case Type::Code::UInt32: + { + return std::make_shared(); + } - case Type::Code::Int8: - { - return std::make_shared(); - } - case Type::Code::Int16: - { - return std::make_shared(); - } - case Type::Code::Int32: - { - return std::make_shared(); - } - case Type::Code::Int64: - { - return std::make_shared(); - } + case Type::Code::Int8: + { + return std::make_shared(); + } + case Type::Code::Int16: + { + return std::make_shared(); + } + case Type::Code::Int32: + { + return std::make_shared(); + } + case Type::Code::Int64: + { + return std::make_shared(); + } + case Type::Code::Int128: + { + return std::make_shared(); + } - case Type::Code::UUID: - { - return std::make_shared(); - } + case Type::Code::UUID: + { + return std::make_shared(); + } - case Type::Code::Float32: - { - return std::make_shared(); - } - case Type::Code::Float64: - { - return std::make_shared(); - } + case Type::Code::Float32: + { + return std::make_shared(); + } + case Type::Code::Float64: + { + return std::make_shared(); + } - case Type::Code::String: - { - return std::make_shared(); - } - case Type::Code::FixedString: - { - string typeName = type->GetName(); - typeName.erase(typeName.find("FixedString("), 12); - typeName.erase(typeName.find(")"), 1); - return std::make_shared(std::stoi(typeName)); - } + case Type::Code::String: + { + return std::make_shared(); + } + case Type::Code::IPv6: + { + return std::make_shared(); + } + case Type::Code::FixedString: + { + string typeName = type->GetName(); + typeName.erase(typeName.find("FixedString("), 12); + typeName.erase(typeName.find(")"), 1); + return std::make_shared(std::stoi(typeName)); + } - case Type::Code::DateTime: - { - return std::make_shared(); - } - case Type::Code::Date: - { - return std::make_shared(); - } + case Type::Code::DateTime: + { + return std::make_shared(); + } + case Type::Code::Date: + { + return std::make_shared(); + } - case Type::Code::Array: - { - return std::make_shared(createColumn(type->GetItemType())); - } + case Type::Code::Array: + { + return std::make_shared(createColumn(type->As()->GetItemType())); + } - case Type::Code::Enum8: - { - std::vector enum_items; - - auto enumType = EnumType(type); - - for (auto ei = enumType.BeginValueToName(); ; ) { - enum_items.push_back( - Type::EnumItem{ei->second, (int8_t)ei->first}); - if (++ei == enumType.EndValueToName()) { - break; - } - } + case Type::Code::Enum8: + { + std::vector enum_items; - return std::make_shared(Type::CreateEnum8(enum_items)); - } - case Type::Code::Enum16: + auto enumType = type->As(); + + for (auto ei = enumType->BeginValueToName();;) { - std::vector enum_items; - - auto enumType = EnumType(type); - - for (auto ei = enumType.BeginValueToName(); ; ) { - enum_items.push_back( - Type::EnumItem{ei->second, (int16_t)ei->first}); - if (++ei == enumType.EndValueToName()) { - break; - } + enum_items.push_back( + Type::EnumItem{ei->second, (int8_t)ei->first}); + if (++ei == enumType->EndValueToName()) + { + break; } - - return std::make_shared(Type::CreateEnum16(enum_items)); } - case Type::Code::Nullable: - { - return std::make_shared(createColumn(type->GetNestedType()), std::make_shared()); - } + return std::make_shared(Type::CreateEnum8(enum_items)); + } + case Type::Code::Enum16: + { + std::vector enum_items; - case Type::Code::Tuple: - { - throw std::runtime_error("can't support Tuple"); - } + auto enumType = type->As(); - case Type::Code::Void: + for (auto ei = enumType->BeginValueToName();;) { - throw std::runtime_error("can't support Void"); + enum_items.push_back( + Type::EnumItem{ei->second, (int16_t)ei->first}); + if (++ei == enumType->EndValueToName()) + { + break; + } } + + return std::make_shared(Type::CreateEnum16(enum_items)); + } + + case Type::Code::Nullable: + { + return std::make_shared(createColumn(type->As()->GetNestedType()), std::make_shared()); } + + case Type::Code::Tuple: + { + throw std::runtime_error("can't support Tuple"); + } + + case Type::Code::Void: + { + throw std::runtime_error("can't support Void"); + } + } + + throw std::runtime_error("createColumn runtime error."); } ColumnRef insertColumn(TypeRef type, zval *value_zval) @@ -178,13 +197,14 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) int keytype; HashTable *values_ht = Z_ARRVAL_P(value_zval); - - switch (type->GetCode()) + try { + switch (type->GetCode()) + { case Type::Code::UInt64: { auto value = std::make_shared(); - + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { convert_to_long(array_value); @@ -193,7 +213,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::UInt8: { @@ -207,7 +226,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::UInt16: { @@ -219,9 +237,29 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + + return value; + } + case Type::Code::IPv4: + { + auto value = std::make_shared(); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) + { + if (Z_TYPE_P(array_value) == IS_STRING) + { + convert_to_string(array_value); + value->Append((string)Z_STRVAL_P(array_value)); + } + else + { + convert_to_long(array_value); + value->Append(Z_LVAL_P(array_value)); + } + } + SC_HASHTABLE_FOREACH_END(); + return value; - break; } case Type::Code::UInt32: { @@ -233,9 +271,8 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Int8: @@ -248,9 +285,8 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Int16: { @@ -262,9 +298,8 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Int32: { @@ -276,9 +311,8 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Int64: { @@ -290,9 +324,8 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) value->Append(Z_LVAL_P(array_value)); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::UUID: @@ -301,14 +334,18 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - if (Z_TYPE_P(array_value) == IS_NULL) { + if (Z_TYPE_P(array_value) == IS_NULL) + { value->Append(UInt128(0, 0)); - } else { + } + else + { convert_to_string(array_value); string value_string = (string)Z_STRVAL_P(array_value); value_string.erase(std::remove(value_string.begin(), value_string.end(), '-'), value_string.end()); - if (value_string.length() != 32) { + if (value_string.length() != 32) + { throw std::runtime_error("UUID format error"); } @@ -321,7 +358,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) } SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::Float32: @@ -336,7 +372,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::Float64: { @@ -350,7 +385,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::String: @@ -382,6 +416,18 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) return value; } + case Type::Code::IPv6: + { + auto value = std::make_shared(); + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) + { + convert_to_string(array_value); + value->Append((string)Z_STRVAL_P(array_value)); + } + SC_HASHTABLE_FOREACH_END(); + + return value; + } case Type::Code::DateTime: { @@ -389,13 +435,21 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - convert_to_long(array_value); - value->Append(Z_LVAL_P(array_value)); + if (Z_TYPE_P(array_value) == IS_STRING) + { + convert_to_string(array_value) + time_t tmp = stringToDatetime((string)Z_STRVAL_P(array_value)); + value->Append(tmp); + } + else + { + convert_to_long(array_value); + value->Append(Z_LVAL_P(array_value)); + } } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Date: { @@ -403,51 +457,63 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - convert_to_long(array_value); - value->Append(Z_LVAL_P(array_value)); + if (Z_TYPE_P(array_value) == IS_STRING) + { + convert_to_string(array_value) + time_t tmp = stringToDatetime((string)Z_STRVAL_P(array_value)); + value->Append(tmp); + } + else + { + convert_to_long(array_value); + value->Append(Z_LVAL_P(array_value)); + } } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Array: { - if (type->GetItemType()->GetCode() == Type::Array) { + auto arrType = type->As(); + if (arrType->GetItemType()->GetCode() == Type::Array) + { throw std::runtime_error("can't support Multidimensional Arrays"); } - auto value = std::make_shared(createColumn(type->GetItemType())); - auto child = createColumn(type->GetItemType()); + auto value = std::make_shared(createColumn(arrType->GetItemType())); + auto child = createColumn(arrType->GetItemType()); SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - if (Z_TYPE_P(array_value) != IS_ARRAY) { + if (Z_TYPE_P(array_value) != IS_ARRAY) + { throw std::runtime_error("The inserted data is not an array type"); } - child->Append(insertColumn(type->GetItemType(), array_value)); + child->Append(insertColumn(arrType->GetItemType(), array_value)); value->AppendAsColumn(child); child->Clear(); } SC_HASHTABLE_FOREACH_END(); - + return value; - break; } case Type::Code::Enum8: { std::vector enum_items; - - auto enumType = EnumType(type); - - for (auto ei = enumType.BeginValueToName(); ; ) { + + auto enumType = type->As(); + + for (auto ei = enumType->BeginValueToName();;) + { enum_items.push_back( Type::EnumItem{ei->second, (int8_t)ei->first}); - if (++ei == enumType.EndValueToName()) { + if (++ei == enumType->EndValueToName()) + { break; } } @@ -456,10 +522,13 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - if (Z_TYPE_P(array_value) == IS_LONG) { + if (Z_TYPE_P(array_value) == IS_LONG) + { convert_to_long(array_value); value->Append(Z_LVAL_P(array_value)); - } else { + } + else + { convert_to_string(array_value); value->Append((string)Z_STRVAL_P(array_value)); } @@ -467,18 +536,19 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::Enum16: { std::vector enum_items; - - auto enumType = EnumType(type); - - for (auto ei = enumType.BeginValueToName(); ; ) { + + auto enumType = type->As(); + + for (auto ei = enumType->BeginValueToName();;) + { enum_items.push_back( Type::EnumItem{ei->second, (int16_t)ei->first}); - if (++ei == enumType.EndValueToName()) { + if (++ei == enumType->EndValueToName()) + { break; } } @@ -487,10 +557,13 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - if (Z_TYPE_P(array_value) == IS_LONG) { + if (Z_TYPE_P(array_value) == IS_LONG) + { convert_to_long(array_value); value->Append(Z_LVAL_P(array_value)); - } else { + } + else + { convert_to_string(array_value); value->Append((string)Z_STRVAL_P(array_value)); } @@ -498,7 +571,6 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_END(); return value; - break; } case Type::Code::Nullable: @@ -507,73 +579,210 @@ ColumnRef insertColumn(TypeRef type, zval *value_zval) SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) { - if (Z_TYPE_P(array_value) == IS_NULL) { + if (Z_TYPE_P(array_value) == IS_NULL) + { nulls->Append(1); - } else { + } + else + { nulls->Append(0); } } SC_HASHTABLE_FOREACH_END(); - ColumnRef child = insertColumn(type->GetNestedType(), value_zval); + ColumnRef child = insertColumn(type->As()->GetNestedType(), value_zval); return std::make_shared(child, nulls); - break; } case Type::Code::Tuple: { - throw std::runtime_error("can't support Tuple"); + size_t values_count = zend_hash_num_elements(values_ht); + + zval *return_should; + SC_MAKE_STD_ZVAL(return_should); + array_init(return_should); + + zval *fzval; + zval *pzval; + + zval *return_tmp; + for (size_t i = 0; i < values_count; i++) + { + SC_MAKE_STD_ZVAL(return_tmp); + array_init(return_tmp); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, pzval) + { + if (Z_TYPE_P(pzval) != IS_ARRAY) + { + throw std::runtime_error("The insert function needs to pass in a two-dimensional array"); + } + fzval = sc_zend_hash_index_find(Z_ARRVAL_P(pzval), i); + if (NULL == fzval) + { + throw std::runtime_error("The number of parameters inserted per line is inconsistent"); + } + sc_zval_add_ref(fzval); + add_next_index_zval(return_tmp, fzval); + } + SC_HASHTABLE_FOREACH_END(); + + add_next_index_zval(return_should, return_tmp); + } + + auto tupleType = type->As()->GetTupleType(); + + std::vector columns; + + int tupleTypeIndex = 0; + + SC_HASHTABLE_FOREACH_START2(Z_ARRVAL_P(return_should), str_key, str_keylen, keytype, array_value) + { + if (Z_TYPE_P(array_value) != IS_ARRAY) + { + throw std::runtime_error("The inserted data is not an array type"); + } + + columns.push_back(insertColumn(tupleType[tupleTypeIndex], array_value)); + tupleTypeIndex++; + } + SC_HASHTABLE_FOREACH_END(); + + sc_zval_ptr_dtor(&return_should); + + return std::make_shared(columns); + } + + case Type::Code::Decimal32: + { + auto value = type->As(); + + auto result = std::make_shared(9, value->GetScale()); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) + { + convert_to_string(array_value); + result->Append((string)Z_STRVAL_P(array_value)); + } + SC_HASHTABLE_FOREACH_END(); + + return result; + } + case Type::Code::Decimal64: + { + auto value = type->As(); + + auto result = std::make_shared(18, value->GetScale()); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) + { + convert_to_string(array_value); + result->Append((string)Z_STRVAL_P(array_value)); + } + SC_HASHTABLE_FOREACH_END(); + + return result; + } + case Type::Code::Decimal128: + { + auto value = type->As(); + + auto result = std::make_shared(38, value->GetScale()); + + SC_HASHTABLE_FOREACH_START2(values_ht, str_key, str_keylen, keytype, array_value) + { + convert_to_string(array_value); + result->Append((string)Z_STRVAL_P(array_value)); + } + SC_HASHTABLE_FOREACH_END(); + + return result; } case Type::Code::Void: { throw std::runtime_error("can't support Void"); } + } + + throw std::runtime_error("insertColumn runtime error."); + } + catch (const std::exception &e) + { + throw e; } } -void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column_name, int8_t is_array) +void convertToZval(zval *arr, const ColumnRef &columnRef, int row, string column_name, int8_t is_array) { - switch (columnRef->Type()->GetCode()) + try { + + switch (columnRef->Type()->GetCode()) + { case Type::Code::UInt64: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::UInt8: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::UInt16: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); + } + break; + } + case Type::Code::IPv4: + { + auto col = columnRef->As()->AsString(row); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)col.data(), col.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)col.data(), col.length(), 1); } break; } case Type::Code::UInt32: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } @@ -581,40 +790,65 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column case Type::Code::Int8: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::Int16: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::Int32: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::Int64: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_long(arr, (long)col); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); + } + break; + } + case Type::Code::Int128: + { + auto col = (*columnRef->As())[row]; + if (is_array) + { + add_next_index_long(arr, (long)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } @@ -624,12 +858,15 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column stringstream first; stringstream second; auto col = (*columnRef->As())[row]; - first<As())[row]; stringstream stream; - stream<>d; - if (is_array) { + stream >> d; + if (is_array) + { add_next_index_double(arr, d); - } else { - sc_add_assoc_double_ex(arr, column_name.c_str(), column_name.length(), d); + } + else + { + sc_add_assoc_double_ex(arr, column_name.data(), column_name.length(), d); } break; } case Type::Code::Float64: { auto col = (*columnRef->As())[row]; - if (is_array) { + if (is_array) + { add_next_index_double(arr, (double)col); - } else { - sc_add_assoc_double_ex(arr, column_name.c_str(), column_name.length(), (double)col); + } + else + { + sc_add_assoc_double_ex(arr, column_name.data(), column_name.length(), (double)col); } break; } @@ -662,41 +905,68 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column case Type::Code::String: { auto col = (*columnRef->As())[row]; - if (is_array) { - sc_add_next_index_stringl(arr, (char*)col.c_str(), col.length(), 1); - } else { - sc_add_assoc_stringl_ex(arr, column_name.c_str(), column_name.length(), (char*)col.c_str(), col.length(), 1); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)col.data(), col.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)col.data(), col.length(), 1); + } + break; + } + + case Type::Code::IPv6: + { + auto col = columnRef->As()->AsString(row); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)col.data(), col.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)col.data(), strlen((char *)col.data()), 1); } break; } + case Type::Code::FixedString: { auto col = (*columnRef->As())[row]; - if (is_array) { - sc_add_next_index_stringl(arr, (char*)col.c_str(), col.length(), 1); - } else { - sc_add_assoc_stringl_ex(arr, column_name.c_str(), column_name.length(), (char*)col.c_str(), strlen((char*)col.c_str()), 1); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)col.data(), col.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)col.data(), strlen((char *)col.data()), 1); } break; } case Type::Code::DateTime: { - auto col = columnRef->As(); - if (is_array) { - add_next_index_long(arr, (long)col->As()->At(row)); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col->As()->At(row)); + auto col = columnRef->As()->At(row); + if (is_array) + { + add_next_index_long(arr, (long)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } case Type::Code::Date: { - auto col = columnRef->As(); - if (is_array) { - add_next_index_long(arr, (long)col->As()->At(row)); - } else { - sc_add_assoc_long_ex(arr, column_name.c_str(), column_name.length(), (zend_ulong)col->As()->At(row)); + auto col = columnRef->As()->At(row); + if (is_array) + { + add_next_index_long(arr, (long)col); + } + else + { + sc_add_assoc_long_ex(arr, column_name.data(), column_name.length(), (zend_ulong)col); } break; } @@ -708,34 +978,44 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column zval *return_tmp; SC_MAKE_STD_ZVAL(return_tmp); array_init(return_tmp); - for (size_t i = 0; i < col->Size(); ++i) { + for (size_t i = 0; i < col->Size(); ++i) + { convertToZval(return_tmp, col, i, "array", 1); } - if (is_array) { + if (is_array) + { add_next_index_zval(arr, return_tmp); - } else { - sc_add_assoc_zval_ex(arr, column_name.c_str(), column_name.length(), return_tmp); + } + else + { + sc_add_assoc_zval_ex(arr, column_name.data(), column_name.length(), return_tmp); } break; } case Type::Code::Enum8: { - auto array = columnRef->As(); - if (is_array) { - sc_add_next_index_stringl(arr, (char*)array->NameAt(row).c_str(), array->NameAt(row).length(), 1); - } else { - sc_add_assoc_stringl_ex(arr, column_name.c_str(), column_name.length(), (char*)array->NameAt(row).c_str(), array->NameAt(row).length(), 1); + auto array = columnRef->As()->NameAt(row); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)array.data(), array.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)array.data(), array.length(), 1); } break; } case Type::Code::Enum16: { - auto array = columnRef->As(); - if (is_array) { - sc_add_next_index_stringl(arr, (char*)array->NameAt(row).c_str(), array->NameAt(row).length(), 1); - } else { - sc_add_assoc_stringl_ex(arr, column_name.c_str(), column_name.length(), (char*)array->NameAt(row).c_str(), array->NameAt(row).length(), 1); + auto array = columnRef->As()->NameAt(row); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)array.data(), array.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)array.data(), array.length(), 1); } break; } @@ -743,13 +1023,19 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column case Type::Code::Nullable: { auto nullable = columnRef->As(); - if (nullable->IsNull(row)) { - if (is_array) { + if (nullable->IsNull(row)) + { + if (is_array) + { add_next_index_null(arr); - } else { - sc_add_assoc_null_ex(arr, column_name.c_str(), column_name.length()); } - } else { + else + { + sc_add_assoc_null_ex(arr, column_name.data(), column_name.length()); + } + } + else + { convertToZval(arr, nullable->Nested(), row, column_name, 0); } break; @@ -757,23 +1043,114 @@ void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column case Type::Code::Tuple: { - throw std::runtime_error("can't support Tuple"); + auto tuple = columnRef->As(); + zval *return_tmp; + SC_MAKE_STD_ZVAL(return_tmp); + array_init(return_tmp); + for (size_t i = 0; i < tuple->Size(); ++i) + { + convertToZval(return_tmp, (*tuple)[i], row, "tuple", 1); + } + if (is_array) + { + add_next_index_zval(arr, return_tmp); + } + else + { + sc_add_assoc_zval_ex(arr, column_name.data(), column_name.length(), return_tmp); + } + break; + } + + case Type::Code::Decimal32: + case Type::Code::Decimal64: + case Type::Code::Decimal128: + { + auto col = columnRef->As(); + auto str = int128_to_string(col->At(row), col->Type()->As()->GetScale()); + if (is_array) + { + sc_add_next_index_stringl(arr, (char *)str.data(), str.length(), 1); + } + else + { + sc_add_assoc_stringl_ex(arr, column_name.data(), column_name.length(), (char *)str.data(), str.length(), 1); + } + break; } case Type::Code::Void: { throw std::runtime_error("can't support Void"); } + } + } + catch (const std::exception &e) + { + throw e; } } -void zvalToBlock(Block& blockDes, Block& blockSrc, zend_ulong num_key, zval *value_zval) +std::string int128_to_string(Int128 value, size_t scale) +{ + std::string result; + const bool sign = value >= 0; + + if (!sign) + { + value = -value; + } + + size_t i = 0; + while (value) + { + if (i == scale) + { + result += static_cast('.'); + } + result += static_cast(value % 10) + '0'; + value /= 10; + i++; + } + + if (result.empty()) + { + result = "0"; + } + else if (!sign) + { + result.push_back('-'); + } + + std::reverse(result.begin(), result.end()); + + return result; +}; + +void zvalToBlock(Block &blockDes, Block &blockSrc, zend_ulong num_key, zval *value_zval) { ColumnRef column = insertColumn(blockSrc[num_key]->Type(), value_zval); - + blockDes.AppendColumn(blockSrc.GetColumnName(num_key), column); } +inline time_t stringToDatetime(std::string str) +{ + char *cha = (char *)str.data(); + tm tm_; + int year, month, day, hour, minute, second; + sscanf(cha, "%d-%d-%d %d:%d:%d", &year, &month, &day, &hour, &minute, &second); + tm_.tm_year = year - 1900; + tm_.tm_mon = month - 1; + tm_.tm_mday = day; + tm_.tm_hour = hour; + tm_.tm_min = minute; + tm_.tm_sec = second; + tm_.tm_isdst = 0; + time_t t_ = mktime(&tm_); + return t_; +} + /* * Local variables: * tab-width: 4 diff --git a/typesToPhp.hpp b/typesToPhp.hpp index a08b67f..18a9fa1 100644 --- a/typesToPhp.hpp +++ b/typesToPhp.hpp @@ -22,10 +22,14 @@ ColumnRef createColumn(TypeRef type); ColumnRef insertColumn(TypeRef type, zval *value_zval); +std::string int128_to_string(Int128 value, size_t scale); + void convertToZval(zval *arr, const ColumnRef& columnRef, int row, string column_name, int8_t is_array); void zvalToBlock(Block& blockDes, Block& blockSrc, zend_ulong num_key, zval *value_zval); +inline time_t stringToDatetime(std::string str); + /* * Local variables: * tab-width: 4