/* Copyright (c) 2000, 2018, Oracle and/or its affiliates. Copyright (c) 2009, 2019, MariaDB Corporation. Copyright (c) 2021 OceanBase Technology Co.,Ltd. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. 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. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */ #include "ma_common.h" #include "errmsg.h" #include "ob_complex.h" #include "ma_string.h" static OB_HASH *global_hash = NULL; static ob_rw_lock_t global_rwlock = OB_RW_INITIALIZER; static void global_hash_free(void *record); // #define UNUSED(x) ((void)x) #define COMPLEX_TYPE_MAX_SQL_LENGTH 32 * 1024 #define COMPLEX_TYPE_MYSQL(M) (MYSQL_EXTENSION_PTR(M)->mysql) #define COMPLEX_TYPE_HASH(M) (MYSQL_EXTENSION_PTR(M)->complex_type_hash) #define COMPLEX_TYPE_USER_TYPES_SQL \ "SELECT "\ " 0 DEPTH, "\ " NULL PARENT_OWNER, "\ " NULL PARENT_TYPE, "\ " TYPE_NAME CHILD_TYPE, "\ " 0 ATTR_NO, "\ " SYS_CONTEXT('USERENV', 'CURRENT_USER') CHILD_TYPE_OWNER, "\ " A.TYPECODE ATTR_TYPE_CODE, "\ " NULL LENGTH, "\ " NULL NUMBER_PRECISION, "\ " NULL SCALE, "\ " NULL CHARACTER_SET_NAME "\ "FROM "\ " USER_TYPES A WHERE TYPE_NAME = '%s' "\ "UNION "\ "( "\ " WITH "\ " CTE_RESULT(PARENT_OWNER, PARENT_TYPE, CHILD_TYPE, ATTR_NO, CHILD_TYPE_OWNER, ATTR_TYPE_CODE, LENGTH, NUMBER_PRECISION, SCALE, CHARACTER_SET_NAME) "\ " AS ( "\ " SELECT "\ " SYS_CONTEXT('USERENV','CURRENT_USER') PARENT_OWNER, "\ " B.TYPE_NAME PARENT_TYPE, "\ " B.ELEM_TYPE_NAME CHILD_TYPE, "\ " 0 ATTR_NO, "\ " B.ELEM_TYPE_OWNER CHILD_TYPE_OWNER, "\ " NVL(A.TYPECODE, B.ELEM_TYPE_NAME) AS ATTR_TYPE_CODE, "\ " B.LENGTH LENGTH, "\ " B.NUMBER_PRECISION NUMBER_PRECISION, "\ " B.SCALE SCALE, "\ " B.CHARACTER_SET_NAME CHARACTER_SET_NAME "\ " FROM "\ " USER_COLL_TYPES B LEFT JOIN USER_TYPES A ON A.TYPE_NAME = B.ELEM_TYPE_NAME "\ " UNION "\ " SELECT "\ " SYS_CONTEXT('USERENV','CURRENT_USER') PARENT_OWNER, "\ " B.TYPE_NAME PARENT_TYPE, "\ " B.ATTR_TYPE_NAME CHILD_TYPE, "\ " B.ATTR_NO ATTR_NO, "\ " B.ATTR_TYPE_OWNER CHILD_TYPE_OWNER, "\ " NVL(A.TYPECODE, B.ATTR_TYPE_NAME) AS ATTR_TYPE_CODE, "\ " B.LENGTH LENGTH, "\ " B.NUMBER_PRECISION NUMBER_PRECISION, "\ " B.SCALE SCALE, "\ " B.CHARACTER_SET_NAME CHARACTER_SET_NAME "\ " FROM USER_TYPE_ATTRS B LEFT JOIN USER_TYPES A ON B.ATTR_TYPE_NAME = A.TYPE_NAME ORDER BY ATTR_NO "\ " ) , "\ " CTE(DEPTH, PARENT_OWNER, PARENT_TYPE, CHILD_TYPE, ATTR_NO, CHILD_TYPE_OWNER, ATTR_TYPE_CODE, LENGTH, NUMBER_PRECISION, SCALE, CHARACTER_SET_NAME) "\ " AS ( "\ " SELECT "\ " 1 DEPTH, "\ " PARENT_OWNER, "\ " PARENT_TYPE, "\ " CHILD_TYPE, "\ " ATTR_NO, "\ " CHILD_TYPE_OWNER, "\ " ATTR_TYPE_CODE, "\ " LENGTH, "\ " NUMBER_PRECISION, "\ " SCALE, CHARACTER_SET_NAME "\ " FROM CTE_RESULT WHERE PARENT_TYPE = '%s' "\ " UNION ALL "\ " SELECT "\ " DEPTH + 1 DEPTH, "\ " CTE_RESULT.PARENT_OWNER, "\ " CTE_RESULT.PARENT_TYPE, "\ " CTE_RESULT.CHILD_TYPE, "\ " CTE_RESULT.ATTR_NO, "\ " CTE_RESULT.CHILD_TYPE_OWNER, "\ " CTE_RESULT.ATTR_TYPE_CODE, "\ " CTE_RESULT.LENGTH, "\ " CTE_RESULT.NUMBER_PRECISION, "\ " CTE_RESULT.SCALE, "\ " CTE_RESULT.CHARACTER_SET_NAME "\ " FROM CTE_RESULT INNER JOIN CTE ON CTE_RESULT.PARENT_TYPE = CTE.CHILD_TYPE "\ " ) "\ " SELECT * FROM CTE "\ "); "\ #define COMPLEX_TYPE_ALL_TYPES_SQL \ "SELECT "\ " 0 DEPTH, "\ " NULL PRAENT_OWNER, "\ " NULL PARENT_TYPE, "\ " to_char(TYPE_NAME) CHILD_TYPE, "\ " 0 ATTR_NO, "\ " OWNER CHILD_TYPE_OWNER, "\ " A.TYPECODE ATTR_TYPE_CODE, "\ " NULL LENGTH, "\ " NULL NUMBER_PRECISION, "\ " NULL SCALE, "\ " NULL CHARACTER_SET_NAME "\ " FROM "\ " ALL_TYPES A WHERE TYPE_NAME = '%s' AND OWNER = '%s' "\ " UNION "\ " ( "\ " WITH "\ " CTE_RESULT(PARENT_OWNER, PARENT_TYPE, CHILD_TYPE, ATTR_NO, CHILD_TYPE_OWNER, ATTR_TYPE_CODE, LENGTH, NUMBER_PRECISION, SCALE, CHARACTER_SET_NAME) "\ " AS ( "\ " SELECT "\ " B.OWNER PARENT_OWNER, "\ " B.TYPE_NAME PARENT_TYPE, "\ " B.ELEM_TYPE_NAME CHILD_TYPE, "\ " 0 ATTR_NO, "\ " B.ELEM_TYPE_OWNER CHILD_TYPE_OWNER, "\ " NVL(A.TYPECODE, B.ELEM_TYPE_NAME) AS ATTR_TYPE_CODE, "\ " B.LENGTH LENGTH, "\ " B.NUMBER_PRECISION NUMBER_PRECISION, "\ " B.SCALE SCALE, "\ " B.CHARACTER_SET_NAME CHARACTER_SET_NAME "\ " FROM "\ " ALL_COLL_TYPES B LEFT JOIN ALL_TYPES A ON A.TYPE_NAME = B.ELEM_TYPE_NAME AND A.OWNER = B.ELEM_TYPE_OWNER "\ " UNION "\ " SELECT "\ " B.OWNER PARENT_OWNER, "\ " B.TYPE_NAME PARENT_TYPE, "\ " B.ATTR_TYPE_NAME CHILD_TYPE, "\ " B.ATTR_NO ATTR_NO, "\ " B.ATTR_TYPE_OWNER CHILD_TYPE_OWNER, "\ " NVL(A.TYPECODE, B.ATTR_TYPE_NAME) AS ATTR_TYPE_CODE, "\ " B.LENGTH LENGTH, "\ " B.NUMBER_PRECISION NUMBER_PRECISION, "\ " B.SCALE SCALE, "\ " B.CHARACTER_SET_NAME CHARACTER_SET_NAME "\ " FROM ALL_TYPE_ATTRS B LEFT JOIN ALL_TYPES A ON A.TYPE_NAME = B.ATTR_TYPE_NAME AND A.OWNER = B.ATTR_TYPE_OWNER ORDER BY ATTR_NO "\ " ) , "\ " CTE(DEPTH, PARENT_OWNER, PARENT_TYPE, CHILD_TYPE, ATTR_NO, CHILD_TYPE_OWNER, ATTR_TYPE_CODE, LENGTH, NUMBER_PRECISION, SCALE, CHARACTER_SET_NAME) "\ " AS ( "\ " SELECT "\ " 1 DEPTH, "\ " PARENT_OWNER, "\ " PARENT_TYPE, "\ " CHILD_TYPE, "\ " ATTR_NO, "\ " CHILD_TYPE_OWNER, "\ " ATTR_TYPE_CODE, "\ " LENGTH, "\ " NUMBER_PRECISION, "\ " SCALE, CHARACTER_SET_NAME "\ " FROM CTE_RESULT WHERE PARENT_TYPE = '%s' AND PARENT_OWNER = '%s' "\ " UNION ALL "\ " SELECT "\ " DEPTH + 1 DEPTH, "\ " CTE_RESULT.PARENT_OWNER, "\ " CTE_RESULT.PARENT_TYPE, "\ " CTE_RESULT.CHILD_TYPE, "\ " CTE_RESULT.ATTR_NO, "\ " CTE_RESULT.CHILD_TYPE_OWNER, "\ " CTE_RESULT.ATTR_TYPE_CODE, "\ " CTE_RESULT.LENGTH, "\ " CTE_RESULT.NUMBER_PRECISION, "\ " CTE_RESULT.SCALE, "\ " CTE_RESULT.CHARACTER_SET_NAME "\ " FROM CTE_RESULT INNER JOIN CTE ON CTE_RESULT.PARENT_TYPE = CTE.CHILD_TYPE AND CTE_RESULT.PARENT_OWNER = CTE.CHILD_TYPE_OWNER "\ " ) "\ " SELECT * FROM CTE "\ "); "\ #define DEPTH_INDEX 0 #define PARENT_TYPE_INDEX 2 #define CHILD_TYPE_INDEX 3 #define ATTR_NO_INDEX 4 #define CHILD_OWNER_INDEX 5 #define ATTR_TYPE_INDEX 6 static enum_types convert_type(const char *type) { if (!strcmp(type, "COLLECTION")) { return TYPE_COLLECTION; } else if (!strcmp(type, "OBJECT")) { return TYPE_OBJECT; } else if (!strcmp(type, "NUMBER")) { return TYPE_NUMBER; } else if (!strcmp(type, "VARCHAR2")) { return TYPE_VARCHAR2; } else if (!strcmp(type, "CHAR")) { return TYPE_CHAR; } else if (!strcmp(type, "DATE")) { return TYPE_DATE; } else if (!strcmp(type, "RAW")) { return TYPE_RAW; } else if (!strcmp(type, "NVARCHAR2")) { return TYPE_NVARCHAR2; } else if (!strcmp(type, "FLOAT")) { return TYPE_OB_NUMBER_FLOAT; } else if (!strncmp(type, "INTERVAL YEAR", 13)) { return TYPE_OB_INTERVAL_YM; } else if (!strncmp(type, "INTERVAL DAY", 12)) { return TYPE_OB_INTERVAL_DS; } else if (!strncmp(type, "TIMESTAMP", 9)) { if (strstr(type, "WITH TIME ZONE")) { return TYPE_OB_TIMESTAMP_WITH_TIME_ZONE; } else if (strstr(type, "WITH LOCAL TIME ZONE")) { return TYPE_OB_TIMESTAMP_WITH_LOCAL_TIME_ZONE; } else { return TYPE_OB_TIMESTAMP_NANO; } } else if (!strcmp(type, "BINARY_FLOAT")) { return TYPE_FLOAT; } else if (!strcmp(type, "BINARY_DOUBLE")) { return TYPE_DOUBLE; } else { return TYPE_MAX; } } static int STDCALL parser_complex(MYSQL_RES *result, OB_HASH *hash) { MYSQL_ROW cur; COMPLEX_TYPE *complex_type; unsigned char *parent_name; COMPLEX_TYPE *parent; while ((cur = mysql_fetch_row(result))) { unsigned int type_size; enum_types type = convert_type(cur[ATTR_TYPE_INDEX]); if (TYPE_OBJECT == type || TYPE_COLLECTION == type) { complex_type = (COMPLEX_TYPE *) hash_search(hash, (unsigned char*)cur[CHILD_TYPE_INDEX], strlen(cur[CHILD_TYPE_INDEX])); if (!complex_type) { type_size = TYPE_COLLECTION == type ? sizeof(COMPLEX_TYPE_COLLECTION) : sizeof(COMPLEX_TYPE_OBJECT); complex_type = (COMPLEX_TYPE *) calloc(1, type_size); if (!complex_type) { return (1); } complex_type->is_valid = 0; complex_type->type = type; if (TYPE_OBJECT == complex_type->type) { ((COMPLEX_TYPE_OBJECT *)complex_type)->attr_no = 0; } /* name 被初始化成了 0, 所以不需要拷贝最后的 NULL 结束符 */ memcpy(complex_type->type_name, cur[CHILD_TYPE_INDEX], strlen(cur[CHILD_TYPE_INDEX])); memcpy(complex_type->owner_name, cur[CHILD_OWNER_INDEX], strlen(cur[CHILD_OWNER_INDEX])); if (hash_insert(hash, (unsigned char *)complex_type)) { return (1); } } else { //ReInit node's info in the query complex_type->is_valid = 0; if (TYPE_OBJECT == complex_type->type) { ((COMPLEX_TYPE_OBJECT *)complex_type)->attr_no = 0; } } } if (atoi(cur[DEPTH_INDEX]) != 0) { parent_name = (unsigned char *)cur[PARENT_TYPE_INDEX]; parent = (COMPLEX_TYPE *) hash_search(hash, parent_name, strlen((char *)parent_name)); if (parent == NULL) { return (1); } if (TYPE_OBJECT == parent->type && ((COMPLEX_TYPE_OBJECT *)parent)->attr_no < strtoul(cur[ATTR_NO_INDEX], NULL, 10)) { ((COMPLEX_TYPE_OBJECT *)parent)->attr_no = strtoul(cur[ATTR_NO_INDEX], NULL, 10); } } } result->data_cursor = result->data->data; while ((cur = mysql_fetch_row(result))) { enum_types child_type; COMPLEX_TYPE_OBJECT *parent_object; COMPLEX_TYPE_COLLECTION *parent_collection; if (atoi(cur[DEPTH_INDEX]) != 0) { parent_name = (unsigned char *)cur[PARENT_TYPE_INDEX]; parent = (COMPLEX_TYPE *) hash_search(hash, parent_name, strlen((char *)parent_name)); if (parent == NULL) { return (1); } child_type = convert_type(cur[ATTR_TYPE_INDEX]); if (TYPE_OBJECT == parent->type) { parent_object = (COMPLEX_TYPE_OBJECT *)parent; if (parent_object->child == NULL) { parent_object->child = (CHILD_TYPE *) calloc(1, parent_object->attr_no * sizeof(CHILD_TYPE)); if (parent_object->child == NULL) { return (1); } } parent_object->child[atoi(cur[ATTR_NO_INDEX]) - 1].type = child_type; if (TYPE_COLLECTION == child_type || TYPE_OBJECT == child_type) { complex_type = (COMPLEX_TYPE *)hash_search(hash, (unsigned char *)cur[CHILD_TYPE_INDEX], strlen(cur[CHILD_TYPE_INDEX])); if (complex_type == NULL) { return (1); } parent_object->child[atoi(cur[ATTR_NO_INDEX]) - 1].object = complex_type; } parent_object->init_attr_no++; if (parent_object->init_attr_no == parent_object->attr_no) { parent->is_valid = 1; } } else if (TYPE_COLLECTION == parent->type) { parent_collection = (COMPLEX_TYPE_COLLECTION *)parent; parent_collection->child.type = child_type; if (TYPE_COLLECTION == child_type || TYPE_OBJECT == child_type) { complex_type = (COMPLEX_TYPE *)hash_search(hash, (unsigned char *)cur[CHILD_TYPE_INDEX], strlen(cur[CHILD_TYPE_INDEX])); if (complex_type == NULL) { return (1); } parent_collection->child.object = complex_type; } parent->is_valid = 1; } } } return (0); } static int STDCALL get_type_from_server(MYSQL *mysql, unsigned char *owner_name, unsigned char *type_name, COMPLEX_HASH *complex_hash) { int retval; MYSQL_RES *result; char sql[COMPLEX_TYPE_MAX_SQL_LENGTH] = {'\0'}; if (NULL != owner_name) { snprintf(sql, COMPLEX_TYPE_MAX_SQL_LENGTH, COMPLEX_TYPE_ALL_TYPES_SQL, type_name, owner_name, type_name, owner_name); } else { /* 如果 owner 为空, 先从 user_types 视图中获取 */ snprintf(sql, COMPLEX_TYPE_MAX_SQL_LENGTH, COMPLEX_TYPE_USER_TYPES_SQL, type_name, type_name); } if (mysql_real_query(mysql, sql, strlen(sql))) { return (1); } if (!(result = mysql_store_result(mysql))) { return (1); /* 如果 user_types 视图中没有该 type, 在再从 all_types 视图中获取 */ } else if (0 == mysql_num_rows(result) && NULL == owner_name) { mysql_free_result(result); snprintf(sql, COMPLEX_TYPE_MAX_SQL_LENGTH, COMPLEX_TYPE_ALL_TYPES_SQL, type_name, "SYS", type_name, "SYS"); if (mysql_real_query(mysql, sql, strlen(sql))) { return (1); } if (!(result = mysql_store_result(mysql))) { return (1); } } ob_rw_wrlock(&(complex_hash->rwlock)); retval = parser_complex(result, complex_hash->hash); ob_rw_unlock(&(complex_hash->rwlock)); mysql_free_result(result); return (retval); } static int STDCALL complex_mysql_init(MYSQL *mysql, MYSQL **complex_mysql) { int ret = 0; *complex_mysql = NULL; if (!(*complex_mysql = mysql_init(*complex_mysql))) { ret = 1; } else if (!mysql_real_connect(*complex_mysql, mysql->host, mysql->user, mysql->passwd, mysql->db, mysql->port, mysql->unix_socket, 0)) { ret = 1; } if (ret != 0 && *complex_mysql != NULL) { mysql_close(*complex_mysql); *complex_mysql = NULL; } return (ret); } static void complex_hash_free(void *record) { COMPLEX_TYPE *header = (COMPLEX_TYPE *)record; if (header->type == TYPE_OBJECT) { free(((COMPLEX_TYPE_OBJECT *)header)->child); } free(header); } static unsigned char *complex_get_hash_key(const unsigned char *record, uint *length, my_bool not_used) { COMPLEX_TYPE *type = (COMPLEX_TYPE *)record; *length= strlen((char *)type->type_name); UNUSED(not_used); return type->type_name; } static int STDCALL complex_hash_init(MYSQL *mysql, unsigned char *hash_key, COMPLEX_HASH **complex_hash) { int ret = 0; *complex_hash = NULL; if (!(*complex_hash = calloc(1, sizeof(COMPLEX_HASH)))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); ret = 1; } else if(ob_rw_init(&((*complex_hash)->rwlock))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); ret = 1; } else if (!((*complex_hash)->hash = calloc(1, sizeof(OB_HASH)))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); ret = 1; } else if (hash_init((*complex_hash)->hash, 0, 0, 0, (hash_get_key) complex_get_hash_key, complex_hash_free, HASH_CASE_INSENSITIVE)) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); ret = 1; } else if (!((*complex_hash)->hash_key = calloc(1, strlen((char *)hash_key) + 1))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); ret = 1; } else { //memset((*complex_hash)->hash_key, 0, strlen((char *)hash_key) + 1); memcpy((*complex_hash)->hash_key, hash_key, strlen((char *)hash_key)); (*complex_hash)->hash_key[strlen((char *)hash_key)] = '\0'; if (hash_insert(global_hash, (unsigned char *)(*complex_hash))) { SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); ret = 1; } } if (ret && *complex_hash != NULL) { global_hash_free((void *)(*complex_hash)); *complex_hash = NULL; } return (ret); } static void global_hash_free(void *record) { COMPLEX_HASH *complex_hash = (COMPLEX_HASH *)record; if (NULL != complex_hash->hash_key) { free(complex_hash->hash_key); } if (NULL != complex_hash->hash) { hash_free(complex_hash->hash); free(complex_hash->hash); } ob_rw_destroy(&(complex_hash->rwlock)); free(complex_hash); } static unsigned char *global_get_hash_key(const unsigned char *record, uint *length, my_bool not_used) { COMPLEX_HASH *complex_hash = (COMPLEX_HASH *)record; *length= strlen((char *)complex_hash->hash_key); UNUSED(not_used); return complex_hash->hash_key; } static int STDCALL global_hash_init(MYSQL *mysql) { if (!(global_hash = calloc(1, sizeof(OB_HASH)))) { SET_CLIENT_ERROR(mysql, CR_OUT_OF_MEMORY, SQLSTATE_UNKNOWN, 0); return 1; } else if (hash_init(global_hash, 0, 0, 0, (hash_get_key) global_get_hash_key, global_hash_free, HASH_CASE_INSENSITIVE)) { hash_free(global_hash); free(global_hash); SET_CLIENT_ERROR(mysql, CR_UNKNOWN_ERROR, SQLSTATE_UNKNOWN, 0); return 1; } return 0; } static const char digits[]= "0123456789abcdef"; char *ma_safe_utoa(int base, ulonglong val, char *buf) { *buf--= 0; do { *buf--= digits[val % base]; } while ((val /= base) != 0); return buf + 1; } static int STDCALL get_complex_hash(MYSQL *mysql, unsigned char *hash_key, int buffer_len, COMPLEX_HASH **complex_hash) { int ret = 0; *complex_hash = NULL; if (NULL == global_hash) { ob_rw_wrlock(&global_rwlock); if (NULL == global_hash && global_hash_init(mysql)) { ret = 1; } ob_rw_unlock(&global_rwlock); } if (ret == 0) { unsigned int hash_length = 0; char port[10] = {'\0'}; char *port_ptr = NULL; port_ptr = ma_safe_utoa(10, mysql->port, &port[sizeof(port)-1]); if (strlen(mysql->host) + strlen(port_ptr) + strlen(mysql->user) + 1 >= (size_t)buffer_len) { ret = 1; } else if ((NULL != mysql->db) && (strlen(mysql->host) + strlen(port_ptr) + strlen(mysql->user) + strlen(mysql->db) + 1 >= (size_t)buffer_len)) { ret = 1; } else { memcpy(hash_key + hash_length, mysql->host, strlen(mysql->host)); hash_length += strlen(mysql->host); memcpy(hash_key + hash_length, port_ptr, strlen(port_ptr)); hash_length += strlen(port_ptr); memcpy(hash_key + hash_length, mysql->user, strlen(mysql->user)); hash_length += strlen(mysql->user); if (NULL != mysql->db) { memcpy(hash_key + hash_length, mysql->db, strlen(mysql->db)); hash_length += strlen(mysql->db); } hash_key[hash_length] = '\0'; ob_rw_rdlock(&global_rwlock); *complex_hash = (COMPLEX_HASH *)hash_search(global_hash, hash_key, strlen((char *)hash_key)); ob_rw_unlock(&global_rwlock); if (NULL == *complex_hash) { ob_rw_wrlock(&global_rwlock); if (NULL == *complex_hash) { if (complex_hash_init(mysql, hash_key, complex_hash)) { ret = 1; } } ob_rw_unlock(&global_rwlock); } } } return (ret); } COMPLEX_TYPE* STDCALL get_complex_type(MYSQL *mysql, unsigned char *owner_name, unsigned char *type_name) { COMPLEX_TYPE *type = NULL; COMPLEX_HASH *complex_hash = NULL; MYSQL *complex_mysql = NULL; unsigned char hash_key[200] = {'\0'}; if (get_complex_hash(mysql, hash_key, 200, &complex_hash)) { } else { ob_rw_rdlock(&(complex_hash->rwlock)); type = (COMPLEX_TYPE *)hash_search(complex_hash->hash, type_name, strlen((char *)type_name)); ob_rw_unlock(&(complex_hash->rwlock)); if (NULL == type || type->is_valid != 1) { if (complex_mysql_init(mysql, &complex_mysql)) { } else if (get_type_from_server(complex_mysql, owner_name, type_name, complex_hash)) { } else { ob_rw_rdlock(&(complex_hash->rwlock)); type = (COMPLEX_TYPE *)hash_search(complex_hash->hash, type_name, strlen((char *)type_name)); ob_rw_unlock(&(complex_hash->rwlock)); } } } if (complex_mysql != NULL) { mysql_close(complex_mysql); complex_mysql = NULL; } if (type && type->is_valid != 1) { return (NULL); } return (type); } COMPLEX_TYPE* STDCALL get_complex_type_with_local(MYSQL *mysql, unsigned char *type_name) { COMPLEX_TYPE *type = NULL; COMPLEX_HASH *complex_hash = NULL; unsigned char hash_key[200] = {'\0'}; memset(hash_key, 0, 200); if (get_complex_hash(mysql, hash_key, 200, &complex_hash)) { } else { ob_rw_rdlock(&(complex_hash->rwlock)); type = (COMPLEX_TYPE *)hash_search(complex_hash->hash, type_name, strlen((char *)type_name)); ob_rw_unlock(&(complex_hash->rwlock)); } if (type && type->is_valid != 1) { return (NULL); } return (type); }