[FEAT MERGE]4_1_sql_feature

Co-authored-by: leslieyuchen <leslieyuchen@gmail.com>
Co-authored-by: Charles0429 <xiezhenjiang@gmail.com>
Co-authored-by: raywill <hustos@gmail.com>
This commit is contained in:
obdev 2023-01-28 16:01:26 +08:00 committed by ob-robot
parent 3080f2b66f
commit 2d19a9d8f5
846 changed files with 161957 additions and 116661 deletions

30
NOTICE
View File

@ -224,33 +224,3 @@ All rights reserved.
This source code is licensed under the BSD-style license found in the
LICENSE file in the root directory of this source tree. An additional grant
of patent rights can be found in the PATENTS file in the same directory
==============================regex==============================
Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
Development of this software was funded, in part, by Cray Research Inc.,
UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
Corporation, none of whom are responsible for the results. The author
thanks all of them.
Redistribution and use in source and binary forms -- with or without
modification -- are permitted for any purpose, provided that
redistributions in source form retain this entire copyright notice and
indicate the origin and nature of any modifications.
I'd appreciate being given credit for this package in the documentation of
software which uses it, but that is not a requirement.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Note that there are some incestuous relationships between this code and NFA
arc maintenance, which perhaps ought to be cleaned up sometime.

View File

@ -241,7 +241,6 @@ install(FILES
deps/oblib/src/lib/queue/ob_fixed_queue.h
deps/oblib/src/lib/queue/ob_link.h
deps/oblib/src/lib/random/ob_random.h
deps/oblib/src/lib/regex/ob_regex.h
deps/oblib/src/lib/resource/achunk_mgr.h
deps/oblib/src/lib/resource/ob_cache_washer.h
deps/oblib/src/lib/resource/ob_resource_mgr.h

View File

@ -1610,6 +1610,7 @@ void easy_connection_on_readable(struct ev_loop *loop, ev_io *w, int revents)
easy_error_log("Failed to do response on client, conn(%p).", c);
}
}
c->status = EASY_CONN_CLOSE_BY_PEER;
} else {
c->conn_has_error = 1;
easy_info_log("Failed to read from connection(%p), n(%d).", c, n);

View File

@ -68,6 +68,7 @@ extern easy_atomic_t easy_debug_uuid;
#define EASY_CONN_CONNECTING 1
#define EASY_CONN_AUTO_CONN 2
#define EASY_CONN_CLOSE 3
#define EASY_CONN_CLOSE_BY_PEER 4
#define EASY_CLIENT_DEFAULT_TIMEOUT 4000
#define EASY_FIRST_MSGLEN 1024

View File

@ -22,6 +22,7 @@ EASY_CPP_START
int easy_localtime(const time_t *t, struct tm *tp);
int64_t easy_time_now();
uint64_t get_cpufreq_khz();
extern int64_t fast_current_time();
EASY_CPP_END

View File

@ -26,6 +26,7 @@ devdeps-zlib-static-1.2.7-132022100815.el7.aarch64.rpm
devdeps-ncurses-static-6.2-72022100815.el7.aarch64.rpm
devdeps-boost-1.74.0-22022110914.el7.aarch64.rpm
devdeps-s2geometry-0.9.0-42022111116.el7.aarch64.rpm
devdeps-icu-69.1-72022112416.el7.aarch64.rpm
[tools]
obdevtools-binutils-2.30-12022100413.el7.aarch64.rpm

View File

@ -28,6 +28,7 @@ devdeps-zlib-static-1.2.7-132022100815.el7.x86_64.rpm
devdeps-ncurses-static-6.2-72022100815.el7.x86_64.rpm
devdeps-boost-1.74.0-22022110914.el7.x86_64.rpm
devdeps-s2geometry-0.9.0-42022111116.el7.x86_64.rpm
devdeps-icu-69.1-72022112416.el7.x86_64.rpm
[tools]
obdevtools-binutils-2.30-12022100413.el7.x86_64.rpm

View File

@ -26,6 +26,7 @@ devdeps-zlib-static-1.2.7-132022100815.el8.aarch64.rpm
devdeps-ncurses-static-6.2-72022100815.el8.aarch64.rpm
devdeps-boost-1.74.0-22022110914.el8.aarch64.rpm
devdeps-s2geometry-0.9.0-42022111116.el8.aarch64.rpm
devdeps-icu-69.1-72022112416.el8.aarch64.rpm
[tools]
obdevtools-binutils-2.30-12022100413.el8.aarch64.rpm

View File

@ -27,6 +27,7 @@ devdeps-zlib-static-1.2.7-132022100815.el8.x86_64.rpm
devdeps-ncurses-static-6.2-72022100815.el8.x86_64.rpm
devdeps-boost-1.74.0-22022110914.el8.x86_64.rpm
devdeps-s2geometry-0.9.0-42022111116.el8.x86_64.rpm
devdeps-icu-69.1-72022112416.el8.x86_64.rpm
[tools]
obdevtools-binutils-2.30-12022100413.el8.x86_64.rpm

View File

@ -22,6 +22,7 @@ target_include_directories(
${DEP_3RD_DIR}/usr/include/
${DEP_3RD_DIR}/usr/local/include
${DEP_DIR}/include/apr-1/
${DEP_DIR}/include/icu/common
)
if (OB_USE_CLANG)
@ -125,6 +126,9 @@ target_link_libraries(oblib_base_base_base
$<$<STREQUAL:"${ARCHITECTURE}","x86_64">:${DEP_DIR}/lib/libunwind.a>
${DEP_DIR}/lib/libz.a
${DEP_DIR}/lib/libs2.a
${DEP_DIR}/lib/libicui18n.a
${DEP_DIR}/lib/libicustubdata.a
${DEP_DIR}/lib/libicuuc.a
-L${DEP_DIR}/var/usr/lib64
-L${DEP_DIR}/var/usr/lib
-L${DEP_3RD_DIR}/usr/lib

View File

@ -15,7 +15,6 @@
#include "lib/ob_define.h"
#include "lib/utility/utility.h"
#include "lib/regex/ob_regex.h"
#include "common/rowkey/ob_rowkey.h"
#include "common/ob_string_buf.h"

View File

@ -2017,8 +2017,7 @@ template <>
ret = databuff_printf(buffer, length, pos, "%s", N_UPPERCASE_CUR_TIMESTAMP);
break;
default:
_OB_LOG(WARN, "ext %ld should not be print as sql", obj.get_ext());
ret = OB_INVALID_ARGUMENT;
ret = databuff_printf(buffer, length, pos, "%s", "Extend Obj");
break;
}
return ret;

View File

@ -633,12 +633,15 @@ struct ObObjPrintParams
uint32_t print_flags_;
struct {
uint32_t need_cast_expr_:1;
uint32_t is_show_create_view_:1;
uint32_t print_origin_stmt_:1;
uint32_t use_memcpy_:1;
uint32_t skip_escape_:1;
uint32_t beginning_space_:1;
uint32_t binary_string_print_hex_:1;
uint32_t reserved_:26;
uint32_t print_with_cte_:1;
uint32_t force_print_cte_:1;
uint32_t need_print_converter_:1;
uint32_t reserved_:23;
};
};
};
@ -1424,7 +1427,7 @@ struct ObDefaultHash : public ObjHashBase
struct ObMurmurHash : public ObjHashBase
{
static uint64_t hash(const void *data, uint64_t len, uint64_t seed)
OB_INLINE static uint64_t hash(const void *data, uint64_t len, uint64_t seed)
{
return murmurhash64A(data, static_cast<int32_t>(len), seed);
}

View File

@ -17,7 +17,6 @@
#include "lib/oblog/ob_log.h"
#include "lib/ob_define.h"
#include "lib/utility/utility.h"
#include "lib/regex/ob_regex.h"
#include "lib/checksum/ob_crc64.h"
#include "lib/json/ob_yson.h"
#include "common/ob_common_utility.h"

View File

@ -25,11 +25,11 @@ extern "C" {
#define SMO_REAL_AS_FLOAT (1ULL) /* support */
#define SMO_PIPES_AS_CONCAT (1ULL << 1) /* support */
#define SMO_ANSI_QUOTES (1ULL << 2) /* support */
#define SMO_IGNORE_SPACE (1ULL << 3) /* not support now */
#define SMO_IGNORE_SPACE (1ULL << 3) /* support but not used */
#define SMO_NOT_USED (1ULL << 4) /* not support now */
#define SMO_ONLY_FULL_GROUP_BY (1ULL << 5) /* support */
#define SMO_NO_UNSIGNED_SUBTRACTION (1ULL << 6) /* support */
#define SMO_NO_DIR_IN_CREATE (1ULL << 7) /* not support */
#define SMO_NO_DIR_IN_CREATE (1ULL << 7) /* support but not used */
#define SMO_POSTGRESQL (1ULL << 8) /*not support*/
#define SMO_ORACLE (1ULL << 9) /*not support*/
#define SMO_MSSQL (1ULL << 10) /*not support*/
@ -55,6 +55,7 @@ extern "C" {
#define SMO_NO_ENGINE_SUBSTITUTION (1ULL << 30) /* support but not used */
#define SMO_PAD_CHAR_TO_FULL_LENGTH (1ULL << 31) /* support */
#define SMO_ERROR_ON_RESOLVE_CAST (1ULL << 32) /* ERROR_ON_RESOLVE_CAST */
#define SMO_TIME_TRUNCATE_FRACTIONAL (1ULL << 33) /* TIME_TRUNCATE_FRACTIONAL */
#define STR_ALLOW_INVALID_DATES "ALLOW_INVALID_DATES"
#define STR_ANSI_QUOTES "ANSI_QUOTES"
@ -90,15 +91,29 @@ extern "C" {
#define STR_POSTGRESQL "POSTGRESQL"
#define STR_MYSQL323 "MYSQL323"
#define STR_MYSQL40 "MYSQL40"
#define STR_COMBINE_TRADITIONAL "STRICT_TRANS_TABLES,STRICT_ALL_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION"
#define STR_COMBINE_ANSI "REAL_AS_FLOAT,PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE"
#define STR_COMBINE_DB2 "PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS"
#define STR_COMBINE_MAXDB "PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER"
#define STR_COMBINE_MSSQL "PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS"
#define STR_COMBINE_ORACLE "PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS,NO_AUTO_CREATE_USER"
#define STR_COMBINE_POSTGRESQL "PIPES_AS_CONCAT,ANSI_QUOTES,IGNORE_SPACE,NO_KEY_OPTIONS,NO_TABLE_OPTIONS,NO_FIELD_OPTIONS"
#define STR_COMBINE_MYSQL323 "HIGH_NOT_PRECEDENCE"
#define STR_COMBINE_MYSQL40 "HIGH_NOT_PRECEDENCE"
#define STR_TIME_TRUNCATE_FRACTIONAL "TIME_TRUNCATE_FRACTIONAL"
#define COMBINE_SMO_TRADITIONAL (SMO_STRICT_TRANS_TABLES | SMO_STRICT_ALL_TABLES | SMO_NO_ZERO_IN_DATE | \
SMO_NO_ZERO_DATE | SMO_ERROR_FOR_DIVISION_BY_ZERO | SMO_NO_AUTO_CREATE_USER | \
SMO_NO_ENGINE_SUBSTITUTION | SMO_TRADITIONAL)
#define COMBINE_SMO_ANSI (SMO_REAL_AS_FLOAT | SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | \
SMO_ANSI)
#define COMBINE_SMO_DB2 (SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | SMO_NO_KEY_OPTIONS | \
SMO_NO_TABLE_OPTIONS | SMO_NO_FIELD_OPTIONS | SMO_DB2)
#define COMBINE_SMO_MAXDB (SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | SMO_NO_KEY_OPTIONS | \
SMO_NO_TABLE_OPTIONS | SMO_NO_FIELD_OPTIONS | SMO_NO_AUTO_CREATE_USER | \
MODE_MAXDB)
#define COMBINE_SMO_MSSQL (SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | SMO_NO_KEY_OPTIONS | \
SMO_NO_TABLE_OPTIONS | SMO_NO_FIELD_OPTIONS | \
SMO_MSSQL)
#define COMBINE_SMO_ORACLE (SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | SMO_NO_KEY_OPTIONS | \
SMO_NO_TABLE_OPTIONS | SMO_NO_FIELD_OPTIONS | SMO_NO_AUTO_CREATE_USER | \
SMO_ORACLE)
#define COMBINE_SMO_POSTGRESQL (SMO_PIPES_AS_CONCAT | SMO_ANSI_QUOTES | SMO_IGNORE_SPACE | SMO_NO_KEY_OPTIONS | \
SMO_NO_TABLE_OPTIONS | SMO_NO_FIELD_OPTIONS | \
SMO_POSTGRESQL)
#define COMBINE_SMO_MYSQL323 (SMO_HIGH_NOT_PRECEDENCE | SMO_MYSQL323)
#define COMBINE_SMO_MYSQL40 (SMO_HIGH_NOT_PRECEDENCE | SMO_MYSQL40)
#define ALL_SMO_COMPACT_MODE (SMO_POSTGRESQL | SMO_ORACLE | SMO_MSSQL | SMO_DB2)

View File

@ -39,9 +39,17 @@ ObSqlModeMap SQL_MODE_MAP[] = {
{SMO_ONLY_FULL_GROUP_BY, STR_ONLY_FULL_GROUP_BY},
{SMO_NO_UNSIGNED_SUBTRACTION, STR_NO_UNSIGNED_SUBTRACTION},
{SMO_NO_DIR_IN_CREATE, STR_NO_DIR_IN_CREATE},
{SMO_POSTGRESQL, STR_POSTGRESQL},
{SMO_ORACLE, STR_ORACLE},
{SMO_MSSQL, STR_MSSQL},
{SMO_DB2, STR_DB2},
{MODE_MAXDB, STR_MAXDB},
{SMO_NO_KEY_OPTIONS, STR_NO_KEY_OPTIONS},
{SMO_NO_TABLE_OPTIONS, STR_NO_TABLE_OPTIONS},
{SMO_NO_FIELD_OPTIONS, STR_NO_FIELD_OPTIONS},
{SMO_MYSQL323, STR_MYSQL323},
{SMO_MYSQL40, STR_MYSQL40},
{SMO_ANSI, STR_ANSI},
{SMO_NO_AUTO_VALUE_ON_ZERO, STR_NO_AUTO_VALUE_ON_ZERO},
{SMO_NO_BACKSLASH_ESCAPES, STR_NO_BACKSLASH_ESCAPES},
{SMO_STRICT_TRANS_TABLES, STR_STRICT_TRANS_TABLES},
@ -50,15 +58,51 @@ ObSqlModeMap SQL_MODE_MAP[] = {
{SMO_NO_ZERO_DATE, STR_NO_ZERO_DATE},
{SMO_ALLOW_INVALID_DATES, STR_ALLOW_INVALID_DATES},
{SMO_ERROR_FOR_DIVISION_BY_ZERO, STR_ERROR_FOR_DIVISION_BY_ZERO},
{SMO_TRADITIONAL, STR_TRADITIONAL},
{SMO_NO_AUTO_CREATE_USER, STR_NO_AUTO_CREATE_USER},
{SMO_HIGH_NOT_PRECEDENCE, STR_HIGH_NOT_PRECEDENCE},
{SMO_NO_ENGINE_SUBSTITUTION, STR_NO_ENGINE_SUBSTITUTION},
{SMO_PAD_CHAR_TO_FULL_LENGTH, STR_PAD_CHAR_TO_FULL_LENGTH},
{SMO_TRADITIONAL, STR_COMBINE_TRADITIONAL}, //Search in order, ensure that combine_str is in front
{SMO_TRADITIONAL, STR_TRADITIONAL},
{SMO_ANSI, STR_COMBINE_ANSI},
{SMO_ANSI, STR_ANSI},
{SMO_ERROR_ON_RESOLVE_CAST, STR_ERROR_ON_RESOLVE_CAST},
{SMO_TIME_TRUNCATE_FRACTIONAL, STR_TIME_TRUNCATE_FRACTIONAL},
{0, NULL}
};
ObSqlModeMap STR_TO_SQL_MODE_MAP[] = {
{SMO_REAL_AS_FLOAT, STR_REAL_AS_FLOAT},
{SMO_PIPES_AS_CONCAT, STR_PIPES_AS_CONCAT},
{SMO_ANSI_QUOTES, STR_ANSI_QUOTES},
{SMO_IGNORE_SPACE, STR_IGNORE_SPACE},
{SMO_NOT_USED, STR_NOT_USED},
{SMO_ONLY_FULL_GROUP_BY, STR_ONLY_FULL_GROUP_BY},
{SMO_NO_UNSIGNED_SUBTRACTION, STR_NO_UNSIGNED_SUBTRACTION},
{SMO_NO_DIR_IN_CREATE, STR_NO_DIR_IN_CREATE},
{COMBINE_SMO_POSTGRESQL, STR_POSTGRESQL},
{COMBINE_SMO_ORACLE, STR_ORACLE},
{COMBINE_SMO_MSSQL, STR_MSSQL},
{COMBINE_SMO_DB2, STR_DB2},
{COMBINE_SMO_MAXDB, STR_MAXDB},
{SMO_NO_KEY_OPTIONS, STR_NO_KEY_OPTIONS},
{SMO_NO_TABLE_OPTIONS, STR_NO_TABLE_OPTIONS},
{SMO_NO_FIELD_OPTIONS, STR_NO_FIELD_OPTIONS},
{COMBINE_SMO_MYSQL323, STR_MYSQL323},
{COMBINE_SMO_MYSQL40, STR_MYSQL40},
{COMBINE_SMO_ANSI, STR_ANSI},
{SMO_NO_AUTO_VALUE_ON_ZERO, STR_NO_AUTO_VALUE_ON_ZERO},
{SMO_NO_BACKSLASH_ESCAPES, STR_NO_BACKSLASH_ESCAPES},
{SMO_STRICT_TRANS_TABLES, STR_STRICT_TRANS_TABLES},
{SMO_STRICT_ALL_TABLES, STR_STRICT_ALL_TABLES},
{SMO_NO_ZERO_IN_DATE, STR_NO_ZERO_IN_DATE},
{SMO_NO_ZERO_DATE, STR_NO_ZERO_DATE},
{SMO_ALLOW_INVALID_DATES, STR_ALLOW_INVALID_DATES},
{SMO_ERROR_FOR_DIVISION_BY_ZERO, STR_ERROR_FOR_DIVISION_BY_ZERO},
{COMBINE_SMO_TRADITIONAL, STR_TRADITIONAL},
{SMO_NO_AUTO_CREATE_USER, STR_NO_AUTO_CREATE_USER},
{SMO_HIGH_NOT_PRECEDENCE, STR_HIGH_NOT_PRECEDENCE},
{SMO_NO_ENGINE_SUBSTITUTION, STR_NO_ENGINE_SUBSTITUTION},
{SMO_PAD_CHAR_TO_FULL_LENGTH, STR_PAD_CHAR_TO_FULL_LENGTH},
{SMO_ERROR_ON_RESOLVE_CAST, STR_ERROR_ON_RESOLVE_CAST},
{SMO_TIME_TRUNCATE_FRACTIONAL, STR_TIME_TRUNCATE_FRACTIONAL},
{0, NULL}
};
@ -81,7 +125,20 @@ ObSQLMode SUPPORT_MODE = SMO_STRICT_ALL_TABLES
| SMO_NO_AUTO_CREATE_USER
| SMO_NO_ENGINE_SUBSTITUTION
| SMO_NO_ZERO_DATE
| SMO_ERROR_FOR_DIVISION_BY_ZERO;
| SMO_ERROR_FOR_DIVISION_BY_ZERO
| SMO_TIME_TRUNCATE_FRACTIONAL
| SMO_NO_DIR_IN_CREATE
| SMO_IGNORE_SPACE
| SMO_REAL_AS_FLOAT
| SMO_ANSI
| SMO_TRADITIONAL
| SMO_POSTGRESQL
| SMO_ORACLE
| SMO_MSSQL
| SMO_DB2
| MODE_MAXDB
| SMO_MYSQL323
| SMO_MYSQL40;
bool is_sql_mode_supported(ObSQLMode mode)
{
@ -107,21 +164,21 @@ int ob_str_to_sql_mode(const ObString &str, ObSQLMode &mode)
NULL != value && OB_SUCC(ret);
value = strtok_r(NULL, ", ", &saveptr)) {
uint64_t i = 0;
for (; NULL != SQL_MODE_MAP[i].str_val && OB_SUCC(ret); ++i) {
for (; NULL != STR_TO_SQL_MODE_MAP[i].str_val && OB_SUCC(ret); ++i) {
// there is no need to use ObCharset::strcmp, because all valid values are comprised of
// ascii character, we can use C string functions instead.
// besides, we are sure that these two strings are both '\0' terminated, so strcasecmp().
if (0 == STRCASECMP(value, SQL_MODE_MAP[i].str_val)) {
tmp_mode |= SQL_MODE_MAP[i].int_val;
if (is_sql_mode_supported(SQL_MODE_MAP[i].int_val)) {
if (0 == STRCASECMP(value, STR_TO_SQL_MODE_MAP[i].str_val)) {
tmp_mode |= STR_TO_SQL_MODE_MAP[i].int_val;
if (is_sql_mode_supported(STR_TO_SQL_MODE_MAP[i].int_val)) {
} else {
LOG_WARN("invalid sql_mode, not supported", KCSTRING(SQL_MODE_MAP[i].str_val));
LOG_WARN("invalid sql_mode, not supported", KCSTRING(STR_TO_SQL_MODE_MAP[i].str_val));
ret = OB_NOT_SUPPORTED;
}
break;
}
}
if (OB_ISNULL(SQL_MODE_MAP[i].str_val) && OB_SUCC(ret)) {
if (OB_ISNULL(STR_TO_SQL_MODE_MAP[i].str_val) && OB_SUCC(ret)) {
ret = OB_ERR_WRONG_VALUE_FOR_VAR;
LOG_WARN("failed to set sql_mode", KCSTRING(value), K(ret));
}

View File

@ -104,6 +104,12 @@ inline bool is_only_full_group_by_on(ObSQLMode mode)
{
return (SMO_ONLY_FULL_GROUP_BY & mode) || lib::is_oracle_mode();
}
inline bool is_time_truncate_fractional(ObSQLMode mode)
{
return (SMO_TIME_TRUNCATE_FRACTIONAL & mode);
}
}
}

View File

@ -1,7 +1,5 @@
add_subdirectory(compress)
add_subdirectory(restore)
add_subdirectory(regex)
target_compile_definitions(regex PRIVATE -DREGEX_STANDALONE -DREGEX_WCHAR)
ob_set_subtarget(oblib_lib ALONE
timezone/ob_timezone_util.cpp

View File

@ -104,6 +104,7 @@ public:
return *this;
}
const ObIAllocator *get_alloc() const { return alloc_;}
ObIAllocator *get_alloc() { return alloc_;}
static uint32_t alloc_offset_bits()
{
DISABLE_WARNING_GCC_PUSH

View File

@ -711,6 +711,7 @@ LABEL_ITEM_DEF(OB_SQL_PS_SQL_META, SqlPsSqlMeta)
LABEL_ITEM_DEF(OB_SQL_PX_BLOOM_FILTER, SqlPxBloomFilte)
LABEL_ITEM_DEF(OB_PS_SESSION_INFO_ARRAY, PsSessiInfoArra)
LABEL_ITEM_DEF(OB_CONNECT_BY_PUMP, ConnectByPump)
LABEL_ITEM_DEF(OB_SQL_PLAN, SqlPlanManger)
//mpimodules
LABEL_ITEM_DEF(OB_MPI_INTERM_RESULT, MpiIntermResult)
@ -1300,7 +1301,7 @@ struct InnerModIds
#undef LABEL_ITEM_DEF
};
enum { LABEL_COUNT_LIMIT = InnerModIds::OB_MOD_END };
STATIC_ASSERT(LABEL_COUNT_LIMIT == 1033, "forbidden to add new label!!!");
STATIC_ASSERT(LABEL_COUNT_LIMIT == 1034, "forbidden to add new label!!!");
};
#define ObNewModIds ObModIds

View File

@ -15,6 +15,7 @@
#include "lib/utility/serialization.h"
#include "lib/ob_define.h"
#include "lib/worker.h"
#include "common/ob_common_utility.h"
namespace oceanbase
{
@ -2608,7 +2609,8 @@ inline bool ObCharset::is_argument_valid(const ObCharsetInfo *cs, const char *st
OB_ISNULL(cs) ||
OB_ISNULL(cs->cset)) {
is_arg_valid = false;
BACKTRACE(ERROR, true, "invalid argument. charset info = %p, str = %p, str_len = %ld", cs, str, str_len);
const ObFatalErrExtraInfoGuard *extra_info = ObFatalErrExtraInfoGuard::get_thd_local_val_ptr();
BACKTRACE(ERROR, true, "invalid argument. charset info = %p, str = %p, str_len = %ld, extra_info=(%s)", cs, str, str_len, (NULL == extra_info) ? NULL : to_cstring(*extra_info));
}
}
return is_arg_valid;

View File

@ -128,7 +128,8 @@ Coercibility Meaning Example
2 Implicit collation Column value, stored routine parameter or local variable
3 System constant such as USER() and VERSION() return value, or system variable
4 Coercible Literal string
5 Ignorable NULL or an expression derived from NULL
5 Numeric or temporal value
6 Ignorable NULL or an expression derived from NULL
for reasons why, please refer to
https://dev.mysql.com/doc/refman/8.0/en/charset-collation-coercibility.html

View File

@ -19490,22 +19490,19 @@ size_t ob_varlen_encoding_gb18030_for_memcmp(const struct ObCharsetInfo* cs,
*is_valid_unicode = 1;
ob_charset_assert(cs != NULL);
sort_order = cs->sort_order;
for (; dst < de && src < se && nweights; nweights--) {
for (; *is_valid_unicode && dst < de && src < se && nweights; nweights--) {
uint mblen = cs->cset->ismbchar(cs, (const char *)src, (const char *)se);
uint weight = 0;
if (mblen > 0) {
weight = get_weight_for_mbchar<INSENSITIVE>(cs, src, mblen);
} else {
weight = get_weight_for_mbchar<INSENSITIVE>(cs, src, mblen);
dst += code_to_gb18030_chs(dst, de - dst, weight);
src += mblen;
} else {
*is_valid_unicode = 0;
weight = sort_order ? sort_order[*src] : *src;
++src;
}
if (weight == 0) {
dst += code_to_gb18030_chs(dst, de - dst, weight);
weight = 0x0000000000000001;
}
dst += code_to_gb18030_chs(dst, de - dst, weight);
src += mblen;
}
++src;
}
}
// adds 0x0000 0000 0000 0000, 0x0000 0000 0000 0000
memset(dst, 0x00, 8);
dst += 8;
@ -19514,8 +19511,8 @@ size_t ob_varlen_encoding_gb18030_for_memcmp(const struct ObCharsetInfo* cs,
uint16_t find_space_char_count_gb18030(const uchar* src, const uchar* se)
{
int space_cnt = 1;
while (*(src+space_cnt) == 0x20 && (src+space_cnt)<se) space_cnt++;
if (space_cnt+src<se) return space_cnt;
while ((src + space_cnt) < se && *(src + space_cnt) == 0x20 ) space_cnt++;
if ((src + space_cnt) < se) return space_cnt;
else return 0;
}
size_t ob_varlen_encoding_gb18030_for_spacecmp(const struct ObCharsetInfo* cs,
@ -19531,7 +19528,7 @@ size_t ob_varlen_encoding_gb18030_for_spacecmp(const struct ObCharsetInfo* cs,
ob_charset_assert(cs != NULL);
sort_order = cs->sort_order;
uint16_t space_cnt = 0xFFFF;
for (; dst < de && src < se && nweights; nweights--) {
for (;*is_valid_unicode && dst < de && src < se && nweights; nweights--) {
// for reslovable multiple bytes, only space's first byte is 0x20,
// in gb18030 encoding scheme
if (*src == 0x20) {
@ -19557,12 +19554,13 @@ size_t ob_varlen_encoding_gb18030_for_spacecmp(const struct ObCharsetInfo* cs,
uint weight = 0;
if (mblen > 0) {
weight = get_weight_for_mbchar<INSENSITIVE>(cs, src, mblen);
dst += code_to_gb18030_chs(dst, de - dst, weight);
src += mblen;
} else {
*is_valid_unicode = 0;
weight = sort_order ? sort_order[*src] : *src;
++src;
}
dst += code_to_gb18030_chs(dst, de - dst, weight);
}
// adds 0x20, 0x20
memset(dst, 0x00, 8);

View File

@ -3539,7 +3539,7 @@ size_t ob_varlen_encoding_gbk_for_memcmp(const struct ObCharsetInfo* cs,
const uchar *sort_order= cs->sort_order;
*is_valid_unicode = 1;
for (; dst < de && src < se && nweights; nweights--)
for (; *is_valid_unicode && dst < de && src < se && nweights; nweights--)
{
if (isgbkhead(*(src)) && (se)-(src)>1 && isgbktail(*((src)+1)))
{
@ -3591,7 +3591,7 @@ size_t ob_varlen_encoding_gbk_for_spacecmp(const struct ObCharsetInfo* cs,
// trim
while (*(se-1) == 0x20 && se>src) se--;
for (; dst < de && src < se && nweights; nweights--)
for (;*is_valid_unicode && dst < de && src < se && nweights; nweights--)
{
int16_t space_cnt = 0;
uint16_t e = 0;

View File

@ -1162,7 +1162,7 @@ static ObCollationHandler ob_collation_utf16_bin_handler =
ob_strnncollsp_utf16_bin,
ob_strnxfrm_unicode_full_bin,
ob_strnxfrmlen_unicode_full_bin,
ob_strnxfrm_unicode_full_bin_varlen,
NULL,
ob_like_range_generic,
ob_wildcmp_utf16_bin,
NULL,
@ -1179,7 +1179,7 @@ static ObCollationHandler ob_collation_utf16_general_ci_handler =
ob_strnncollsp_utf16,
ob_strnxfrm_unicode,
ob_strnxfrmlen_simple,
ob_strnxfrm_unicode_varlen,
NULL,/*ob_strnxfrm_unicode_varlen_utf16,*/
ob_like_range_generic,
ob_wildcmp_utf16_ci,
NULL,

View File

@ -2321,7 +2321,7 @@ size_t ob_varlen_encoding_for_memcmp(const struct ObCharsetInfo* cs,
wc = 0;
ob_charset_assert(src);
*is_valid_unicode = 1;
for (; dst < de && nweights; nweights--)
for (;*is_valid_unicode && src < se && dst < de && nweights; nweights--)
{
if ((res= cs->cset->mb_wc(cs, &wc, src, se)) <= 0) {
if (src < se) {
@ -2353,8 +2353,8 @@ size_t ob_varlen_encoding_for_memcmp(const struct ObCharsetInfo* cs,
uint16_t find_space_char_count(const uchar* src, const uchar* se)
{
int space_cnt = 1;
while (*(src+space_cnt) == 0x20 && (src+space_cnt)<se) space_cnt++;
if (space_cnt+src<se) return space_cnt;
while ((src + space_cnt) < se && *(src + space_cnt) == 0x20) space_cnt++;
if ((src + space_cnt) < se) return space_cnt;
else return 0;
}
size_t ob_varlen_encoding_for_spacecmp(const struct ObCharsetInfo* cs,
@ -2372,7 +2372,7 @@ size_t ob_varlen_encoding_for_spacecmp(const struct ObCharsetInfo* cs,
ob_charset_assert(src);
*is_valid_unicode = 1;
uint16_t space_cnt = 0xFFFF;
for (; dst < de && nweights; nweights--)
for (;*is_valid_unicode && src < se && dst < de && nweights; nweights--)
{
// for reslovable multiple bytes, only space's first byte is 0x20,
// in utf8 encoding scheme.

View File

@ -444,6 +444,8 @@ public:
ObBitSet(const ObBitSet &other);
template <int64_t O_N, typename O_ALLOC, bool O_AUTO_FREE>
ObBitSet &operator=(const ObBitSet<O_N, O_ALLOC, O_AUTO_FREE> &other);
template <int64_t O_N, typename O_ALLOC, bool O_AUTO_FREE>
int assign(const ObBitSet<O_N, O_ALLOC, O_AUTO_FREE> &other);
bool operator==(const ObBitSet &other) const;
bool equal(const ObBitSet &other) const;
@ -912,6 +914,16 @@ ObBitSet<N, BlockAllocatorT, auto_free> &ObBitSet<N, BlockAllocatorT, auto_free>
return *this;
}
template <int64_t N, typename BlockAllocatorT, bool auto_free> template <int64_t O_N, typename O_ALLOC, bool O_AUTO_FREE>
int ObBitSet<N, BlockAllocatorT, auto_free>::assign(const ObBitSet<O_N, O_ALLOC, O_AUTO_FREE> &other)
{
int ret = OB_SUCCESS;
if (static_cast<void *>(this) != &other) {
ret = bitset_word_array_.assign(other.bitset_word_array_);
}
return ret;
}
template <int64_t N, typename BlockAllocatorT, bool auto_free>
bool ObBitSet<N, BlockAllocatorT, auto_free>::operator==(const ObBitSet &other) const
{

View File

@ -195,8 +195,8 @@ int ObBinaryHeap<T, CompareFunctor, LOCAL_ARRAY_SIZE>::upheap(int64_t index)
index = parent;
}
array_.at(index) = tmp;
if (OB_SUCC(cmp_.get_error_code())) {
array_.at(index) = tmp;
record_index(index);
reset_root_cmp_cache();
}
@ -229,6 +229,7 @@ int ObBinaryHeap<T, CompareFunctor, LOCAL_ARRAY_SIZE>::downheap(int64_t index)
index = picked_child;
}
array_.at(index) = tmp;
if (OB_SUCC(cmp_.get_error_code())) {
if (index == get_root()) {
// We did not change anything in the tree except for the value
@ -240,7 +241,6 @@ int ObBinaryHeap<T, CompareFunctor, LOCAL_ARRAY_SIZE>::downheap(int64_t index)
// the tree changed, reset cache
reset_root_cmp_cache();
}
array_.at(index) = tmp;
record_index(index);
}
return ret;

View File

@ -453,9 +453,9 @@ public:
if (!is_zero()) {
const int32_t exp_val = get_decode_exp(d_);
if (exp_val >= 0) {
ret_len += std::max(exp_val + 1, static_cast<int32_t>(d_.len_)) * MAX_STORE_LEN;
ret_len += std::max(exp_val + 1, static_cast<int32_t>(d_.len_)) * DIGIT_LEN;
} else {
ret_len += (0 - exp_val + static_cast<int32_t>(d_.len_)) * MAX_STORE_LEN;
ret_len += (0 - exp_val + static_cast<int32_t>(d_.len_)) * DIGIT_LEN;
}
}
return ret_len;

View File

@ -85,6 +85,7 @@ const int64_t OB_MAX_CLIENT_INFO_LENGTH = 64;
const int64_t OB_MAX_MOD_NAME_LENGTH = 48;
const int64_t OB_MAX_ACT_NAME_LENGTH = 32;
const int64_t OB_MAX_UUID_LENGTH = 16;
const int64_t OB_MAX_UUID_STR_LENGTH = 36;
const int64_t MAX_ZONE_LENGTH = 128;
const int64_t MAX_REGION_LENGTH = 128;
const int64_t MAX_GTS_NAME_LENGTH = 128;
@ -156,6 +157,9 @@ const uint64_t SEARRAY_INIT_NUM = 4;
const int64_t OB_DEFAULT_TABLE_DOP = 1;
const int64_t OB_DEFAULT_META_OBJ_PERCENTAGE_LIMIT = 10;
const uint64_t OB_DEFAULT_COLUMN_SRS_ID = 0xffffffffffffffe0;
const int64_t OB_MAX_SPAN_LENGTH = 1024;
const int64_t OB_MAX_SPAN_TAG_LENGTH = 8 * 1024L;
const int64_t OB_MAX_REF_TYPE_LENGTH = 10;
// See ObDeviceHealthStatus for more information
const int64_t OB_MAX_DEVICE_HEALTH_STATUS_STR_LENGTH = 20;
@ -789,6 +793,7 @@ const int64_t SYS_MAX_ALLOCATE_MEMORY = 1L << 34;
// mem factor
const double SQL_AUDIT_MEM_FACTOR = 0.1;
const double SQL_PLAN_MEM_FACTOR = 0.1;
const double MONITOR_MEM_FACTOR = 0.01;
const double KVCACHE_FACTOR = TENANT_RESERVE_MEM_RATIO;
@ -1570,12 +1575,21 @@ const int64_t OB_MAX_NUMBER_PRECISION = 38; //Number in Oracle: p:[1, 3
const int64_t OB_MAX_NUMBER_PRECISION_INNER = 40; //Number in Oracle: p can reach 40 if not define by user
const int64_t OB_MIN_NUMBER_SCALE = -84; //Number in Oracle: s:[-84, 127]
const int64_t OB_MAX_NUMBER_SCALE = 127; //Number in Oracle: s:[-84, 127]
// len_ = 2, se_ = 192: 2 digits(e.g: 111.111)
const uint32_t NUM_DESC_2DIGITS_POSITIVE_DECIMAL = 0xc0000002;
// len_ = 1, se_ = 191: 1 digit fragment(e.g 0.111)
const uint32_t NUM_DESC_1DIGIT_POSITIVE_FRAGMENT = 0xbf000001;
// len_ = 1, se_ = 192: 1 digit integer(e.g 111)
const uint32_t NUM_DESC_1DIGIT_POSITIVE_INTEGER = 0xc0000001;
// len_ = 2, se_ = 64: 2 digits(e.g: -111.111)
const uint32_t NUM_DESC_2DIGITS_NEGATIVE_DECIMAL = 0x40000002;
// len_ = 1, se_ = 65: 1 digit fragment(e.g -0.111)
const uint32_t NUM_DESC_1DIGIT_NEGATIVE_FRAGMENT = 0x41000001;
// len_ = 1, se_ = 64: 1 digit integer(e.g -111)
const uint32_t NUM_DESC_1DIGIT_NEGATIVE_INTEGER = 0x40000001;
const int64_t OB_DECIMAL_NOT_SPECIFIED = -1;
const int64_t OB_MIN_NUMBER_FLOAT_PRECISION = 1; //Float in Oracle: p[1, 126]
const int64_t OB_MAX_NUMBER_FLOAT_PRECISION = 126;
@ -2072,6 +2086,12 @@ enum ObWFRemoveMode
REMOVE_EXTRENUM = 2
};
enum ObTraceGranularity
{
QUERY_LEVEL = 0,
TRANS_LEVEL = 1
};
} // end namespace common
} // end namespace oceanbase
@ -2166,6 +2186,7 @@ struct ObNumberDesc
explicit ObNumberDesc(const uint32_t desc): desc_(desc) {}
explicit ObNumberDesc(const uint8_t len, uint8_t flag, uint8_t exp, uint8_t sign)
: len_(len), reserved_(0), flag_(flag), exp_(exp), sign_(sign) {}
bool is_2d_positive_decimal()
{
return (desc_ == oceanbase::common::NUM_DESC_2DIGITS_POSITIVE_DECIMAL);
@ -2178,6 +2199,20 @@ struct ObNumberDesc
{
return (desc_ == oceanbase::common::NUM_DESC_1DIGIT_POSITIVE_INTEGER);
}
bool is_2d_negative_decimal()
{
return (desc_ == oceanbase::common::NUM_DESC_2DIGITS_NEGATIVE_DECIMAL);
}
bool is_1d_negative_fragment()
{
return (desc_ == oceanbase::common::NUM_DESC_1DIGIT_NEGATIVE_FRAGMENT);
}
bool is_1d_negative_integer()
{
return (desc_ == oceanbase::common::NUM_DESC_1DIGIT_NEGATIVE_INTEGER);
}
union
{
uint32_t desc_;

View File

@ -219,6 +219,7 @@
#define N_FROZEN_VERSION "frozen_version"
#define N_VERSION "version"
#define N_OB_VERSION "ob_version"
#define N_ICU_VERSION "icu_version"
#define N_CONNECTION_ID "connection_id"
#define N_SESSIONTIMEZONE "sessiontimezone"
#define N_DBTIMEZONE "dbtimezone"
@ -319,6 +320,11 @@
#define N_END_VAL "end_value"
#define N_INCLUDE_START "include_start"
#define N_INCLUDE_END "include_end"
#define N_IS_STRICT_IN "is_strict_in"
#define N_CONTAIN_QUESTIONMARK "contain_questionmark"
#define N_OFFSETS "offsets"
#define N_MISSING_OFFSETS "missing_offsets"
#define N_IN_PARAMS "in_params"
#define N_PATTERN_VAL "pattern"
#define N_ESCAPE_VAL "escape"
#define N_ALWAYS_TRUE "always_true"
@ -489,6 +495,8 @@
#define N_COALESCE "coalesce"
#define N_NVL "nvl"
#define N_NVL2 "nvl2"
#define N_FORMAT_BYTES "format_bytes"
#define N_FORMAT_PICO_TIME "format_pico_time"
#define N_EXPR_TYPE "expr_type"
#define N_DIM "dimension"
#define N_CASE "case"
@ -785,6 +793,9 @@
#define N_UUID "uuid"
#define N_UUID_SHORT "uuid_short"
#define N_SYS_GUID "sys_guid"
#define N_UUID_TO_BIN "uuid_to_bin"
#define N_IS_UUID "is_uuid"
#define N_BIN_TO_UUID "bin_to_uuid"
#define N_SET_TO_STR "set_to_str"
#define N_ENUM_TO_STR "enum_to_str"
#define N_SET_TO_INNER_TYPE "set_to_inner_type"
@ -803,6 +814,7 @@
#define N_CHR "chr"
#define N_EXP "exp"
#define N_CALC_UROWID "calc_urowid"
#define N_NAME_CONST "name_const"
//for dll udf
#define N_NORMAL_UDF "dll_normal_user_defined_function"
#define N_AGG_UDF "dll_agg_user_defined_function"
@ -824,6 +836,11 @@
#define N_AES_ENCRYPT "aes_encrypt"
#define N_AES_DECRYPT "aes_decrypt"
#define N_DECODE "decode"
#define N_ENCODE "encode"
#define N_DES_DECRYPT "des_decrypt"
#define N_DES_ENCRYPT "des_encrypt"
#define N_ENCRYPT "encrypt"
#define N_UID "uid"

View File

@ -1,10 +0,0 @@
# Define object library regex
oblib_add_library(regex
regex/regcomp.cpp
regex/regexec.cpp
regex/regerror.cpp
regex/regfree.cpp
regex/regalone.cpp
ob_regex.cpp
ob_regex.h)
target_link_libraries(regex oblib_base)

View File

@ -1,110 +0,0 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX LIB
#include <stdlib.h>
#include "lib/oblog/ob_log.h"
#include "lib/allocator/ob_malloc.h"
#include "lib/regex/ob_regex.h"
namespace oceanbase
{
namespace common
{
ObRegex::ObRegex()
: init_(false),
match_(NULL),
reg_(),
nmatch_(0)
{
}
ObRegex::~ObRegex()
{
if (true == init_) {
destroy();
}
}
int ObRegex::init(const char* pattern, int flags)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(true == init_)) {
ret = OB_NOT_INIT;
LOG_WARN("already inited", K(ret), K(this));
} else if (OB_ISNULL(pattern)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid param pattern", K(ret), KP(pattern));
} else {
int tmp_ret = regcomp(&reg_, pattern, flags);
if (OB_UNLIKELY(0 != tmp_ret)) {
ret = OB_ERR_REGEXP_ERROR;
LOG_WARN("fail to regcomp", K(ret), K(tmp_ret));
} else {
nmatch_ = reg_.re_nsub + 1;
ObMemAttr attr;
attr.label_ = ObModIds::OB_REGEX;
match_ = (regmatch_t*)ob_malloc(sizeof(regmatch_t) * nmatch_, attr);
if (OB_ISNULL(match_)) {
ret = OB_ERR_REGEXP_ERROR;
LOG_WARN("fail to create the regmatch object", K(ret));
regfree(&reg_);
} else {
init_ = true;
}
}
}
return ret;
}
int ObRegex::match(const char* text, int flags, bool &is_match)
{
int ret = OB_SUCCESS;
is_match = false;
if (OB_UNLIKELY(!init_)) {
ret = OB_NOT_INIT;
LOG_WARN("not inited", K(ret), K(this));
} else if (OB_ISNULL(text)) {
ret = OB_INVALID_ARGUMENT;
LOG_WARN("invalid param text", K(ret), KP(text));
} else {
int tmp_ret = regexec(&reg_, text, nmatch_, match_, flags);
if (REG_NOMATCH == tmp_ret) {
is_match = false;
} else if (0 == tmp_ret) {
is_match = true;
} else {
ret = OB_ERR_REGEXP_ERROR;
const static int64_t REG_ERR_MSG_BUF_LEN = 512;
char reg_err_msg[REG_ERR_MSG_BUF_LEN];
size_t err_msg_len = regerror(tmp_ret, &reg_, reg_err_msg, REG_ERR_MSG_BUF_LEN);
LOG_WARN("fail to run match func: regexec", K(ret),
K(tmp_ret), K(err_msg_len), KCSTRING(reg_err_msg));
}
}
return ret;
}
void ObRegex::destroy()
{
if (init_) {
regfree(&reg_);
if (NULL != match_) {
ob_free(match_);
match_ = NULL;
}
nmatch_ = 0;
init_ = false;
}
}
}
}

View File

@ -1,52 +0,0 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef OCEANBASE_LIB_REGEX_OB_REGEX_
#define OCEANBASE_LIB_REGEX_OB_REGEX_
#include <regex.h>
#include "lib/ob_define.h"
namespace oceanbase
{
namespace common
{
class ObRegex
{
public:
ObRegex();
virtual ~ObRegex();
public:
int init(const char* pattern, int flags);
int match(const char* text, int flags, bool &is_match);
void destroy();
inline const regmatch_t* get_match() const
{
return match_;
}
inline int64_t get_match_count() const
{
return static_cast<int64_t>(nmatch_);
}
private:
bool init_;
regmatch_t* match_;
regex_t reg_;
size_t nmatch_;
private:
DISALLOW_COPY_AND_ASSIGN(ObRegex);
};
}
}
#endif //OCEANBASE_LIB_REGEX_OB_REGEX_

View File

@ -1,84 +0,0 @@
This regular expression package was originally developed by Henry Spencer.
It bears the following copyright notice:
**********************************************************************
Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
Development of this software was funded, in part, by Cray Research Inc.,
UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
Corporation, none of whom are responsible for the results. The author
thanks all of them.
Redistribution and use in source and binary forms -- with or without
modification -- are permitted for any purpose, provided that
redistributions in source form retain this entire copyright notice and
indicate the origin and nature of any modifications.
I'd appreciate being given credit for this package in the documentation
of software which uses it, but that is not a requirement.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**********************************************************************
Oceanbase adopted the code out of Tcl 8.4.1. Portions of regc_locale.c
and re_syntax.n were developed by Tcl developers other than Henry; these
files bear the Tcl copyright and license notice:
**********************************************************************
This software is copyrighted by the Regents of the University of
California, Sun Microsystems, Inc., Scriptics Corporation, ActiveState
Corporation and other parties. The following terms apply to all files
associated with the software unless explicitly disclaimed in
individual files.
The authors hereby grant permission to use, copy, modify, distribute,
and license this software and its documentation for any purpose, provided
that existing copyright notices are retained in all copies and that this
notice is included verbatim in any distributions. No written agreement,
license, or royalty fee is required for any of the authorized uses.
Modifications to this software may be copyrighted by their authors
and need not follow the licensing terms described here, provided that
the new terms are clearly indicated on the first page of each file where
they apply.
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE
IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
MODIFICATIONS.
GOVERNMENT USE: If you are acquiring this software on behalf of the
U.S. government, the Government shall have only "Restricted Rights"
in the software and related documentation as defined in the Federal
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you
are acquiring the software on behalf of the Department of Defense, the
software shall be classified as "Commercial Computer Software" and the
Government shall have only "Restricted Rights" as defined in Clause
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
authors grant the U.S. Government and others acting in its behalf
permission to use and distribute the software in accordance with the
terms specified in this license.
**********************************************************************
Subsequent modifications to the code by the Oceanbase project follow
the same license terms as the rest of Oceanbase.

View File

@ -1,55 +0,0 @@
This is a port to make standalone available the Henry Spencer's Regex Library
from Tcl 8.6a2.
In the hope that the Tcl developers take this port as the base for their RE
module, great effort was paid to not update the *.c files, sadly it was not
possible. Some *.h files suffered dirty updates for the same reasons.
To build and test
make
./regtest_hsrex.sh
To rebuild
make clean
make
To build against the other library uncomment the proper line in the file
regtest_hsrex.sh and execute again.
# Either this one
$CC -I. -I$H/inc -L. -lhsrex -o $rgbin $rgsrc
# or this one
#$CC -I. -I$H/inc -L. -lhswrex -DREGEX_WCHAR -o $rgbin $rgsrc
You would like to test with debuging information. Uncomment the proper line in
the Makefile and rebuild.
# Either this one
#CFLAGS = -DREGEX_STANDALONE -fPIC -DREG_DEBUG -g
# Or this one
CFLAGS = -DREGEX_STANDALONE -fPIC -D_NDEBUG -O3
Two libraries are provided, libhsrex.so and libhswrex.so. The first one is for
ascii character code and the second one for wide characters. Both libraries
were tested in Linux and Solaris. Compiling and runing in Window$ should be
easy.
The following entry point where defined in each library:
ob_re_comp() (ob_re_wcomp() for wide char) to compile a RE
ob_re_exec() (ob_re_wexec() for wide char) to parse data against a compiled RE.
ob_regfree() To dispose the memory of a compiled RE.
ob_regerror() Translates error codes to ascii strings.
It is pretty easy to add support for a ob_regcomp() regexec() front end. That
front end functions should take care of UTF-8 to wide charater conversion, for
instance.
The regression test script regtest_hsrex.sh contains an example of how to use
the libraries. It just test cases I was interested on. Adding more use cases to
that script should be easy.
Send any comments to Walter Waldo <wawasa@gmail.com>
Enjoy it,
Walter Waldo.

View File

@ -1,340 +0,0 @@
#ifndef OCEANBASE_LIB_REGEX_REGEX_OB_REGEX_
#define OCEANBASE_LIB_REGEX_REGEX_OB_REGEX_ /* never again */
/*
* regular expressions
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Prototypes etc. marked with "^" within comments get gathered up (and
* possibly edited) by the regfwd program and inserted near the bottom of this
* file.
*
* We offer the option of declaring one wide-character version of the RE
* functions as well as the char versions. To do that, define __REG_WIDE_T to
* the type of wide characters (unfortunately, there is no consensus that
* wchar_t is suitable) and __REG_WIDE_COMPILE and __REG_WIDE_EXEC to the
* names to be used for the compile and execute functions (suggestion:
* re_Xcomp and re_Xexec, where X is a letter suggestive of the wide type,
* e.g. re_ucomp and re_uexec for Unicode). For cranky old compilers, it may
* be necessary to do something like:
* #define __REG_WIDE_COMPILE(a,b,c,d) re_Xcomp(a,b,c,d)
* #define __REG_WIDE_EXEC(a,b,c,d,e,f,g) re_Xexec(a,b,c,d,e,f,g)
* rather than just #defining the names as parameterless macros.
*
* For some specialized purposes, it may be desirable to suppress the
* declarations of the "front end" functions, ob_regcomp() and ob_regexec(), or of
* the char versions of the compile and execute functions. To suppress the
* front-end functions, define __REG_NOFRONT. To suppress the char versions,
* define __REG_NOCHAR.
*
* The right place to do those defines (and some others you may want, see
* below) would be <sys/types.h>. If you don't have control of that file, the
* right place to add your own defines to this file is marked below. This is
* normally done automatically, by the makefile and regmkhdr, based on the
* contents of regcustom.h.
*/
#include "common/ob_common_utility.h"
/*
* voodoo for C++
*/
#ifdef __cplusplus
extern "C" {
#endif
/*
* Add your own defines, if needed, here.
*/
/*
* Location where a chunk of regcustom.h is automatically spliced into this
* file (working from its prototype, regproto.h).
*/
/* --- begin --- */
/* ensure certain things don't sneak in from system headers */
#ifdef __REG_WIDE_T
#undef __REG_WIDE_T
#endif
#ifdef __REG_WIDE_COMPILE
#undef __REG_WIDE_COMPILE
#endif
#ifdef __REG_WIDE_EXEC
#undef __REG_WIDE_EXEC
#endif
#ifdef __REG_REGOFF_T
#undef __REG_REGOFF_T
#endif
#ifdef __REG_VOID_T
#undef __REG_VOID_T
#endif
#ifdef __REG_CONST
#undef __REG_CONST
#endif
#ifdef __REG_NOFRONT
#undef __REG_NOFRONT
#endif
#ifdef __REG_NOCHAR
#undef __REG_NOCHAR
#endif
/* interface types */
#define __REG_WIDE_T Ob_UniChar
#define __REG_REGOFF_T long /* not really right, but good enough... */
#define __REG_VOID_T void
#define __REG_CONST const
/* names and declarations */
#define __REG_WIDE_COMPILE ObReComp
#define __REG_WIDE_EXEC ObReExec
#define __REG_NOFRONT /* don't want ob_regcomp() and ob_regexec() */
#define __REG_NOCHAR /* or the char versions */
#define ob_regfree ObReFree
#define ob_regerror ObReError
/* --- end --- */
#ifdef REGEX_STANDALONE
# undef ob_regfree
# undef ob_regerror
# define ob_regfree ob_re_free
# define ob_regerror ob_re_error
# undef __REG_WIDE_T
# define __REG_WIDE_T wchar_t
# undef __REG_WIDE_COMPILE
# define __REG_WIDE_COMPILE ob_re_wcomp
# undef __REG_WIDE_EXEC
# define __REG_WIDE_EXEC ob_re_wexec
# ifndef REGEX_WCHAR
# undef __REG_NOCHAR
# endif
#endif
/*
* interface types etc.
*/
/*
* ob_regoff_t has to be large enough to hold either off_t or ssize_t, and must
* be signed; it's only a guess that long is suitable, so we offer
* <sys/types.h> an override.
*/
#ifdef __REG_REGOFF_T
typedef __REG_REGOFF_T ob_regoff_t;
#else
typedef long ob_regoff_t;
#endif
/*
* For benefit of old compilers, we offer <sys/types.h> the option of
* overriding the `void' type used to declare nonexistent return types.
*/
#ifdef __REG_VOID_T
typedef __REG_VOID_T re_void;
#else
typedef void re_void;
#endif
/*
* Also for benefit of old compilers, <sys/types.h> can supply a macro which
* expands to a substitute for `const'.
*/
#ifndef __REG_CONST
#define __REG_CONST const
#endif
/*
* other interface types
*/
/* the biggie, a compiled RE (or rather, a front end to same) */
typedef struct {
int re_magic; /* magic number */
size_t re_nsub; /* number of subexpressions */
long re_info; /* information about RE */
#define OB_REG_UBACKREF 000001
#define OB_REG_ULOOKAHEAD 000002
#define OB_REG_UBOUNDS 000004
#define OB_REG_UBRACES 000010
#define OB_REG_UBSALNUM 000020
#define OB_REG_UPBOTCH 000040
#define OB_REG_UBBS 000100
#define OB_REG_UNONPOSIX 000200
#define OB_REG_UUNSPEC 000400
#define OB_REG_UUNPORT 001000
#define OB_REG_ULOCALE 002000
#define OB_REG_UEMPTYMATCH 004000
#define OB_REG_UIMPOSSIBLE 010000
#define OB_REG_USHORTEST 020000
int re_csize; /* sizeof(character) */
const wchar_t *re_endp; /* backward compatibility kludge */
/* the rest is opaque pointers to hidden innards */
char *re_guts; /* `char *' is more portable than `void *' */
char *re_fns;
} ob_regex_t;
/* result reporting (may acquire more fields later) */
typedef struct {
ob_regoff_t rm_so; /* start of substring */
ob_regoff_t rm_eo; /* end of substring */
} ob_regmatch_t;
/* supplementary control and reporting */
typedef struct {
ob_regmatch_t rm_extend; /* see REG_EXPECT */
} ob_rm_detail_t;
/*
* compilation
^ #ifndef __REG_NOCHAR
^ int ob_re_comp(ob_regex_t *, __REG_CONST char *, size_t, int);
^ #endif
^ #ifndef __REG_NOFRONT
^ int ob_regcomp(ob_regex_t *, __REG_CONST char *, int);
^ #endif
^ #ifdef __REG_WIDE_T
^ int __REG_WIDE_COMPILE(ob_regex_t *, __REG_CONST __REG_WIDE_T *, size_t, int);
^ #endif
*/
#define OB_REG_BASIC 000000 /* BREs (convenience) */
#define OB_REG_EXTENDED 000001 /* EREs */
#define OB_REG_ADVF 000002 /* advanced features in EREs */
#define OB_REG_ADVANCED 000003 /* AREs (which are also EREs) */
#define OB_REG_QUOTE 000004 /* no special characters, none */
#define OB_REG_NOSPEC REG_QUOTE /* historical synonym */
#define OB_REG_ICASE 000010 /* ignore case */
#define OB_REG_NOSUB 000020 /* don't care about subexpressions */
#define OB_REG_EXPANDED 000040 /* expanded format, white space & comments */
#define OB_REG_NLSTOP 000100 /* \n doesn't match . or [^ ] */
#define OB_REG_NLANCH 000200 /* ^ matches after \n, $ before */
#define OB_REG_NEWLINE 000300 /* newlines are line terminators */
#define OB_REG_PEND 000400 /* ugh -- backward-compatibility hack */
#define OB_REG_EXPECT 001000 /* report details on partial/limited matches */
#define OB_REG_BOSONLY 002000 /* temporary kludge for BOS-only matches */
#define OB_REG_DUMP 004000 /* none of your business :-) */
#define OB_REG_FAKE 010000 /* none of your business :-) */
#define OB_REG_PROGRESS 020000 /* none of your business :-) */
#define OB_REG_ORACLE_MODE 040000/*distinguish is oracle or mysql call regexp*/
/*
* execution
^ #ifndef __REG_NOCHAR
^ int ob_re_exec(ob_regex_t *, __REG_CONST char *, size_t,
^ ob_rm_detail_t *, size_t, ob_regmatch_t [], int);
^ #endif
^ #ifndef __REG_NOFRONT
^ int ob_regexec(ob_regex_t *, __REG_CONST char *, size_t, ob_regmatch_t [], int);
^ #endif
^ #ifdef __REG_WIDE_T
^ int __REG_WIDE_EXEC(ob_regex_t *, __REG_CONST __REG_WIDE_T *, size_t,
^ ob_rm_detail_t *, size_t, ob_regmatch_t [], int);
^ #endif
*/
#define OB_REG_NOTBOL 0001 /* BOS is not BOL */
#define OB_REG_NOTEOL 0002 /* EOS is not EOL */
#define OB_REG_STARTEND 0004 /* backward compatibility kludge */
#define OB_REG_FTRACE 0010 /* none of your business */
#define OB_REG_MTRACE 0020 /* none of your business */
#define OB_REG_SMALL 0040 /* none of your business */
/*
* misc generics (may be more functions here eventually)
^ re_void ob_regfree(ob_regex_t *);
*/
/*
* error reporting
* Be careful if modifying the list of error codes -- the table used by
* ob_regerror() is generated automatically from this file!
*
* Note that there is no wide-char variant of ob_regerror at this time; what kind
* of character is used for error reports is independent of what kind is used
* in matching.
*
^ extern size_t ob_regerror(int, __REG_CONST ob_regex_t *, char *, size_t);
*/
#define OB_REG_OKAY 0 /* no errors detected */
#define OB_REG_NOMATCH 1 /* failed to match */
#define OB_REG_BADPAT 2 /* invalid regexp */
#define OB_REG_ECOLLATE 3 /* invalid collating element */
#define OB_REG_ECTYPE 4 /* invalid character class */
#define OB_REG_EESCAPE 5 /* invalid escape \ sequence */
#define OB_REG_ESUBREG 6 /* invalid backreference number */
#define OB_REG_EBRACK 7 /* brackets [] not balanced */
#define OB_REG_EPAREN 8 /* parentheses () not balanced */
#define OB_REG_EBRACE 9 /* braces {} not balanced */
#define OB_REG_BADBR 10 /* invalid repetition count(s) */
#define OB_REG_ERANGE 11 /* invalid character range */
#define OB_REG_ESPACE 12 /* out of memory */
#define OB_REG_BADRPT 13 /* quantifier operand invalid */
#define OB_REG_ASSERT 15 /* "can't happen" -- you found a bug */
#define OB_REG_INVARG 16 /* invalid argument to regex function */
#define OB_REG_MIXED 17 /* character widths of regex and string differ */
#define OB_REG_BADOPT 18 /* invalid embedded option */
#define OB_REG_ETOOBIG 19 /* nfa has too many states */
/* two specials for debugging and testing */
#define OB_REG_ATOI 101 /* convert error-code name to number */
#define OB_REG_ITOA 102 /* convert error-code number to name */
/*
* the prototypes, as possibly munched by regfwd
*/
/* =====^!^===== begin forwards =====^!^===== */
/* automatically gathered by fwd; do not hand-edit */
/* === regproto.h === */
#ifndef __REG_NOCHAR
int ob_re_comp(ob_regex_t *, __REG_CONST unsigned char *, size_t, int);
#endif
#ifndef __REG_NOFRONT
int ob_regcomp(ob_regex_t *, __REG_CONST char *, int);
#endif
#ifdef __REG_WIDE_T
MODULE_SCOPE int __REG_WIDE_COMPILE(ob_regex_t *, __REG_CONST __REG_WIDE_T *, size_t, int);
#endif
#ifndef __REG_NOCHAR
int ob_re_exec(ob_regex_t *, __REG_CONST unsigned char *, size_t, ob_rm_detail_t *, size_t, ob_regmatch_t [], int);
#endif
#ifndef __REG_NOFRONT
int ob_regexec(ob_regex_t *, __REG_CONST char *, size_t, ob_regmatch_t [], int);
#endif
#ifdef __REG_WIDE_T
MODULE_SCOPE int __REG_WIDE_EXEC(ob_regex_t *, __REG_CONST __REG_WIDE_T *, size_t, ob_rm_detail_t *, size_t, ob_regmatch_t [], int);
#endif
MODULE_SCOPE re_void ob_regfree(ob_regex_t *);
MODULE_SCOPE size_t ob_regerror(int, __REG_CONST ob_regex_t *, char *, size_t);
/* automatically gathered by fwd; do not hand-edit */
/* =====^!^===== end forwards =====^!^===== */
/*
* more C++ voodoo
*/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,265 +0,0 @@
#ifdef REGEX_WCHAR
#include "regcustom.h"
/*
*----------------------------------------------------------------------
*
* Ob_DStringInit --
*
* Initializes a dynamic string, discarding any previous contents of the
* string Ob_DStringFree should have been called already if the dynamic
* string was previously in use).
*
* Results:
* None.
*
* Side effects:
* The dynamic string is initialized to be empty.
*
*----------------------------------------------------------------------
*/
void
Ob_DStringInit(
Ob_DString *dsPtr) /* Pointer to structure for dynamic string. */
{
dsPtr->string = dsPtr->staticSpace;
dsPtr->length = 0;
dsPtr->spaceAvl = OB_DSTRING_STATIC_SIZE;
dsPtr->staticSpace[0] = '\0';
}
/*
*----------------------------------------------------------------------
*
* Ob_DStringSetLength --
*
* Change the length of a dynamic string. This can cause the string to
* either grow or shrink, depending on the value of length.
*
* Results:
* None.
*
* Side effects:
* The length of dsPtr is changed to length and a null byte is stored at
* that position in the string. If length is larger than the space
* allocated for dsPtr, then a panic occurs.
*
*----------------------------------------------------------------------
*/
void
Ob_DStringSetLength(
Ob_DString *dsPtr, /* Structure describing dynamic string. */
int length) /* New length for dynamic string. */
{
int newsize;
if (length < 0) {
length = 0;
}
if (length >= dsPtr->spaceAvl) {
/*
* There are two interesting cases here. In the first case, the user
* may be trying to allocate a large buffer of a specific size. It
* would be wasteful to overallocate that buffer, so we just allocate
* enough for the requested size plus the trailing null byte. In the
* second case, we are growing the buffer incrementally, so we need
* behavior similar to Ob_DStringAppend. The requested length will
* usually be a small delta above the current spaceAvl, so we'll end
* up doubling the old size. This won't grow the buffer quite as
* quickly, but it should be close enough.
*/
newsize = dsPtr->spaceAvl * 2;
if (length < newsize) {
dsPtr->spaceAvl = newsize;
} else {
dsPtr->spaceAvl = length + 1;
}
if (dsPtr->string == dsPtr->staticSpace) {
char *newString = (char *) ckalloc((unsigned) dsPtr->spaceAvl);
memcpy(newString, dsPtr->string, (size_t) dsPtr->length);
dsPtr->string = newString;
} else {
dsPtr->string = (char *) ckrealloc((void *) dsPtr->string,
(size_t) dsPtr->spaceAvl);
}
}
dsPtr->length = length;
dsPtr->string[length] = 0;
}
/*
*----------------------------------------------------------------------
*
* Ob_DStringFree --
*
* Frees up any memory allocated for the dynamic string and reinitializes
* the string to an empty state.
*
* Results:
* None.
*
* Side effects:
* The previous contents of the dynamic string are lost, and the new
* value is an empty string.
*
*----------------------------------------------------------------------
*/
void
Ob_DStringFree(
Ob_DString *dsPtr) /* Structure describing dynamic string. */
{
if (dsPtr->string != dsPtr->staticSpace) {
ckfree(dsPtr->string);
}
dsPtr->string = dsPtr->staticSpace;
dsPtr->length = 0;
dsPtr->spaceAvl = OB_DSTRING_STATIC_SIZE;
dsPtr->staticSpace[0] = '\0';
}
/*
* Unicode characters less than this value are represented by themselves in
* UTF-8 strings.
*/
#define UNICODE_SELF 0x80
/*
*---------------------------------------------------------------------------
*
* Ob_UniCharToUtf --
*
* Store the given Ob_UniChar as a sequence of UTF-8 bytes in the
* provided buffer. Equivalent to Plan 9 runetochar().
*
* Results:
* The return values is the number of bytes in the buffer that were
* consumed.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
INLINE int Ob_UniCharToUtf(
int ch, /* The Ob_UniChar to be stored in the
* buffer. */
char *buf) /* Buffer in which the UTF-8 representation of
* the Ob_UniChar is stored. Buffer must be
* large enough to hold the UTF-8 character
* (at most Ob_UTF_MAX bytes). */
{
if ((ch > 0) && (ch < UNICODE_SELF)) {
buf[0] = (char) ch;
return 1;
}
if (ch >= 0) {
if (ch <= 0x7FF) {
buf[1] = (char) ((ch | 0x80) & 0xBF);
buf[0] = (char) ((ch >> 6) | 0xC0);
return 2;
}
if (ch <= 0xFFFF) {
three:
buf[2] = (char) ((ch | 0x80) & 0xBF);
buf[1] = (char) (((ch >> 6) | 0x80) & 0xBF);
buf[0] = (char) ((ch >> 12) | 0xE0);
return 3;
}
#if Ob_UTF_MAX > 3
if (ch <= 0x1FFFFF) {
buf[3] = (char) ((ch | 0x80) & 0xBF);
buf[2] = (char) (((ch >> 6) | 0x80) & 0xBF);
buf[1] = (char) (((ch >> 12) | 0x80) & 0xBF);
buf[0] = (char) ((ch >> 18) | 0xF0);
return 4;
}
if (ch <= 0x3FFFFFF) {
buf[4] = (char) ((ch | 0x80) & 0xBF);
buf[3] = (char) (((ch >> 6) | 0x80) & 0xBF);
buf[2] = (char) (((ch >> 12) | 0x80) & 0xBF);
buf[1] = (char) (((ch >> 18) | 0x80) & 0xBF);
buf[0] = (char) ((ch >> 24) | 0xF8);
return 5;
}
if (ch <= 0x7FFFFFFF) {
buf[5] = (char) ((ch | 0x80) & 0xBF);
buf[4] = (char) (((ch >> 6) | 0x80) & 0xBF);
buf[3] = (char) (((ch >> 12) | 0x80) & 0xBF);
buf[2] = (char) (((ch >> 18) | 0x80) & 0xBF);
buf[1] = (char) (((ch >> 24) | 0x80) & 0xBF);
buf[0] = (char) ((ch >> 30) | 0xFC);
return 6;
}
#endif
}
ch = 0xFFFD;
goto three;
}
/*
*---------------------------------------------------------------------------
*
* Ob_UniCharToUtfDString --
*
* Convert the given Unicode string to UTF-8.
*
* Results:
* The return value is a pointer to the UTF-8 representation of the
* Unicode string. Storage for the return value is appended to the end of
* dsPtr.
*
* Side effects:
* None.
*
*---------------------------------------------------------------------------
*/
char * Ob_UniCharToUtfDString(
const Ob_UniChar *uniStr, /* Unicode string to convert to UTF-8. */
int uniLength, /* Length of Unicode string in Ob_UniChars
* (must be >= 0). */
Ob_DString *dsPtr) /* UTF-8 representation of string is appended
* to this previously initialized DString. */
{
const Ob_UniChar *w, *wEnd;
char *p, *string;
int oldLength;
/*
* UTF-8 string length in bytes will be <= Unicode string length *
* Ob_UTF_MAX.
*/
oldLength = Ob_DStringLength(dsPtr);
Ob_DStringSetLength(dsPtr, (oldLength + uniLength + 1) * Ob_UTF_MAX);
string = Ob_DStringValue(dsPtr) + oldLength;
p = string;
wEnd = uniStr + uniLength;
for (w = uniStr; w < wEnd; ) {
p += Ob_UniCharToUtf(*w, p);
w++;
}
Ob_DStringSetLength(dsPtr, oldLength + (p - string));
return string;
}
#endif /* REGEX_WCHAR */

View File

@ -1,246 +0,0 @@
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef REGEX_STANDALONE
# define REGEX_STANDALONE
#endif
#ifdef REGEX_WCHAR
# include <wctype.h>
# include <wchar.h>
typedef wchar_t chr;
typedef chr Ob_UniChar;
#else
# include <ctype.h>
typedef unsigned char chr;
typedef wchar_t Ob_UniChar;
#endif
/*
* In The standalone version we are more concerned with performance,
* so an automatic var is our best choice.
*/
#define AllocVars(vPtr) \
struct vars regex_autovar; \
register struct vars *vPtr = &regex_autovar;
#define MALLOC(n) calloc(1,n)
#define FREE(p) free(VS(p))
#define REALLOC(p,n) realloc(VS(p),n)
#define ckalloc(n) calloc(1,n)
#define ckrealloc(p,n) realloc(p,n)
#define ckfree(p) free(p)
#ifdef REGEX_WCHAR
# define Ob_UniCharToLower(c) towlower(c)
# define Ob_UniCharToUpper(c) towupper(c)
# define Ob_UniCharToTitle(c) towupper(c)
# define Ob_UniCharIsAlpha(c) iswalpha(c)
# define Ob_UniCharIsAlnum(c) iswalnum(c)
# define Ob_UniCharIsDigit(c) iswdigit(c)
# define Ob_UniCharIsSpace(c) iswspace(c)
#else
# define Ob_DStringInit(ds)
# define Ob_UniCharToUtfDString(s,l,ds) (s)
# define Ob_DStringFree(ds)
# define Ob_UniCharToLower(c) tolower(c)
# define Ob_UniCharToUpper(c) toupper(c)
# define Ob_UniCharToTitle(c) toupper(c)
# define Ob_UniCharIsAlpha(c) isalpha(c)
# define Ob_UniCharIsAlnum(c) isalnum(c)
# define Ob_UniCharIsDigit(c) isdigit(c)
# define Ob_UniCharIsSpace(c) isspace(c)
#endif
/*
* The maximum number of bytes that are necessary to represent a single
* Unicode character in UTF-8. The valid values should be 3 or 6 (or perhaps 1
* if we want to support a non-unicode enabled core). If 3, then Ob_UniChar
* must be 2-bytes in size (UCS-2) (the default). If 6, then Ob_UniChar must
* be 4-bytes in size (UCS-4). At this time UCS-2 mode is the default and
* recommended mode. UCS-4 is experimental and not recommended. It works for
* the core, but most extensions expect UCS-2.
*/
#ifndef Ob_UTF_MAX
#define Ob_UTF_MAX 3
#endif
/*
* The structure defined below is used to hold dynamic strings. The only
* fields that clients should use are string and length, accessible via the
* macros Ob_DStringValue and Ob_DStringLength.
*/
#define OB_DSTRING_STATIC_SIZE 200
typedef struct Ob_DString {
char *string; /* Points to beginning of string: either
* staticSpace below or a malloced array. */
int length; /* Number of non-NULL characters in the
* string. */
int spaceAvl; /* Total number of bytes available for the
* string and its terminating NULL char. */
char staticSpace[OB_DSTRING_STATIC_SIZE];
/* Space to use in common case where string is
* small. */
} Ob_DString;
#define Ob_DStringLength(dsPtr) ((dsPtr)->length)
#define Ob_DStringValue(dsPtr) ((dsPtr)->string)
/*
* The macro below is used to modify a "char" value (e.g. by casting it to an
* unsigned character) so that it can be used safely with macros such as
* isspace.
*/
#define UCHAR(c) ((unsigned char) (c))
/*
* Used to tag functions that are only to be visible within the module being
* built and not outside it (where this is supported by the linker).
*/
#ifndef MODULE_SCOPE
# ifdef __cplusplus
# define MODULE_SCOPE extern "C"
#else
# define MODULE_SCOPE extern
#endif
#endif
/*
* Macros used to declare a function to be exported by a DLL. Used by Windows,
* maps to no-op declarations on non-Windows systems. The default build on
* windows is for a DLL, which causes the DLLIMPORT and DLLEXPORT macros to be
* nonempty. To build a static library, the macro STATIC_BUILD should be
* defined.
*
* Note: when building static but linking dynamically to MSVCRT we must still
* correctly decorate the C library imported function. Use CRTIMPORT
* for this purpose. _DLL is defined by the compiler when linking to
* MSVCRT.
*/
#if (defined(__WIN32__) && (defined(_MSC_VER) || (__BORLANDC__ >= 0x0550) || defined(__LCC__) || defined(__WATCOMC__) || (defined(__GNUC__) && defined(__declspec))))
# define HAVE_DECLSPEC 1
# ifdef STATIC_BUILD
# define DLLIMPORT
# define DLLEXPORT
# ifdef _DLL
# define CRTIMPORT __declspec(dllimport)
# else
# define CRTIMPORT
# endif
# else
# define DLLIMPORT __declspec(dllimport)
# define DLLEXPORT __declspec(dllexport)
# define CRTIMPORT __declspec(dllimport)
# endif
#else
# define DLLIMPORT
# if defined(__GNUC__) && __GNUC__ > 3
# define DLLEXPORT __attribute__ ((visibility("default")))
# else
# define DLLEXPORT
# endif
# define CRTIMPORT
#endif
/*
* These macros are used to control whether functions are being declared for
* import or export. If a function is being declared while it is being built
* to be included in a shared library, then it should have the DLLEXPORT
* storage class. If is being declared for use by a module that is going to
* link against the shared library, then it should have the DLLIMPORT storage
* class. If the symbol is beind declared for a static build or for use from a
* stub library, then the storage class should be empty.
*
* The convention is that a macro called BUILD_xxxx, where xxxx is the name of
* a library we are building, is set on the compile line for sources that are
* to be placed in the library. When this macro is set, the storage class will
* be set to DLLEXPORT. At the end of the header file, the storage class will
* be reset to DLLIMPORT.
*/
#undef Ob_STORAGE_CLASS
#ifdef BUILD_Ob
# define Ob_STORAGE_CLASS DLLEXPORT
#else
# ifdef USE_Ob_STUBS
# define Ob_STORAGE_CLASS
# else
# define Ob_STORAGE_CLASS DLLIMPORT
# endif
#endif
/*
* Definitions that allow this header file to be used either with or without
* ANSI C features like function prototypes.
*/
#undef _ANSI_ARGS_
#ifndef INLINE
# define INLINE
#endif
#ifndef NO_CONST
# define CONST1 const
#else
# define CONST1
#endif
#ifndef NO_PROTOTYPES
# define _ANSI_ARGS_(x) x
#else
# define _ANSI_ARGS_(x) ()
#endif
#ifdef USE_NON_CONST
# ifdef USE_COMPAT_CONST
# error define at most one of USE_NON_CONST and USE_COMPAT_CONST
# endif
# define CONST84
# define CONST84_RETURN
#else
# ifdef USE_COMPAT_CONST
# define CONST84
# define CONST84_RETURN CONST1
# else
# define CONST84 CONST1
# define CONST84_RETURN CONST1
# endif
#endif
#ifndef CONST86
# define CONST86 CONST1
#endif
/*
* Make sure EXTERN isn't defined elsewhere
*/
#ifdef EXTERN
# undef EXTERN
#endif /* EXTERN */
#ifdef __cplusplus
# define EXTERN extern "C" Ob_STORAGE_CLASS
#else
# define EXTERN extern Ob_STORAGE_CLASS
#endif
#ifdef REGEX_WCHAR
EXTERN void Ob_DStringFree (Ob_DString * dsPtr);
EXTERN void Ob_DStringInit (Ob_DString * dsPtr);
EXTERN char * Ob_UniCharToUtfDString (CONST1 Ob_UniChar * uniStr,
int uniLength, Ob_DString * dsPtr);
EXTERN void Ob_DStringSetLength (Ob_DString * dsPtr,
int length);
#endif /* REGEX_WCHAR */

View File

@ -1,856 +0,0 @@
/*
* colorings of characters
* This file is #included by regcomp.c.
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Note that there are some incestuous relationships between this code and NFA
* arc maintenance, which perhaps ought to be cleaned up sometime.
*/
#define CISERR() VISERR(cm->v)
#define CERR(e) VERR(cm->v, (e))
/*
- initcm - set up new colormap
^ static void initcm(struct vars *, struct colormap *);
*/
static void
initcm(
struct vars *v,
struct colormap *cm)
{
int i;
int j;
union tree *t;
union tree *nextt;
struct colordesc *cd;
cm->magic = CMMAGIC;
cm->v = v;
cm->ncds = NINLINECDS;
cm->cd = cm->cdspace;
cm->max = 0;
cm->free = 0;
cd = cm->cd; /* cm->cd[WHITE] */
cd->sub = NOSUB;
cd->arcs = NULL;
cd->flags = 0;
cd->nchrs = CHR_MAX - CHR_MIN + 1;
/*
* Upper levels of tree.
*/
for (t=&cm->tree[0], j=NBYTS-1 ; j>0 ; t=nextt, j--) {
nextt = t + 1;
for (i=BYTTAB-1 ; i>=0 ; i--) {
t->tptr[i] = nextt;
}
}
/*
* Bottom level is solid white.
*/
t = &cm->tree[NBYTS-1];
for (i=BYTTAB-1 ; i>=0 ; i--) {
t->tcolor[i] = WHITE;
}
cd->block = t;
}
/*
- freecm - free dynamically-allocated things in a colormap
^ static void freecm(struct colormap *);
*/
static void
freecm(
struct colormap *cm)
{
size_t i;
union tree *cb;
cm->magic = 0;
if (NBYTS > 1) {
cmtreefree(cm, cm->tree, 0);
}
for (i=1 ; i<=cm->max ; i++) { /* skip WHITE */
if (!UNUSEDCOLOR(&cm->cd[i])) {
cb = cm->cd[i].block;
if (cb != NULL) {
FREE(cb);
}
}
}
if (cm->cd != cm->cdspace) {
FREE(cm->cd);
}
}
/*
- cmtreefree - free a non-terminal part of a colormap tree
^ static void cmtreefree(struct colormap *, union tree *, int);
*/
static void
cmtreefree(
struct colormap *cm,
union tree *tree,
int level) /* level number (top == 0) of this block */
{
int i;
union tree *t;
union tree *fillt = &cm->tree[level+1];
union tree *cb;
assert(level < NBYTS-1); /* this level has pointers */
for (i=BYTTAB-1 ; i>=0 ; i--) {
t = tree->tptr[i];
assert(t != NULL);
if (t != fillt) {
if (level < NBYTS-2) { /* more pointer blocks below */
cmtreefree(cm, t, level+1);
FREE(t);
} else { /* color block below */
cb = cm->cd[t->tcolor[0]].block;
if (t != cb) { /* not a solid block */
FREE(t);
}
}
}
}
}
/*
- setcolor - set the color of a character in a colormap
^ static color setcolor(struct colormap *, pchr, pcolor);
*/
static color /* previous color */
setcolor(
struct colormap *cm,
pchr c,
pcolor co)
{
uchr uc = c;
int shift;
int level;
int b;
int bottom;
union tree *t;
union tree *newt;
union tree *fillt;
union tree *lastt;
union tree *cb;
color prev;
assert(cm->magic == CMMAGIC);
if (CISERR() || co == COLORLESS) {
return COLORLESS;
}
t = cm->tree;
for (level=0, shift=BYTBITS*(NBYTS-1) ; shift>0; level++, shift-=BYTBITS){
b = (uc >> shift) & BYTMASK;
lastt = t;
t = lastt->tptr[b];
assert(t != NULL);
fillt = &cm->tree[level+1];
bottom = (shift <= BYTBITS) ? 1 : 0;
cb = (bottom) ? cm->cd[t->tcolor[0]].block : fillt;
if (t == fillt || t == cb) { /* must allocate a new block */
newt = (union tree *) MALLOC((bottom) ?
sizeof(struct colors) : sizeof(struct ptrs));
if (newt == NULL) {
CERR(OB_REG_ESPACE);
return COLORLESS;
}
if (bottom) {
memcpy(newt->tcolor, t->tcolor, BYTTAB*sizeof(color));
} else {
memcpy(newt->tptr, t->tptr, BYTTAB*sizeof(union tree *));
}
t = newt;
lastt->tptr[b] = t;
}
}
b = uc & BYTMASK;
prev = t->tcolor[b];
t->tcolor[b] = (color) co;
return prev;
}
/*
- maxcolor - report largest color number in use
^ static color maxcolor(struct colormap *);
*/
static color
maxcolor(
struct colormap *cm)
{
if (CISERR()) {
return COLORLESS;
}
return (color) cm->max;
}
/*
- newcolor - find a new color (must be subject of setcolor at once)
* Beware: may relocate the colordescs.
^ static color newcolor(struct colormap *);
*/
static color /* COLORLESS for error */
newcolor(
struct colormap *cm)
{
struct colordesc *cd;
size_t n;
if (CISERR()) {
return COLORLESS;
}
if (cm->free != 0) {
assert(cm->free > 0);
assert((size_t) cm->free < cm->ncds);
cd = &cm->cd[cm->free];
assert(UNUSEDCOLOR(cd));
assert(cd->arcs == NULL);
cm->free = cd->sub;
} else if (cm->max < cm->ncds - 1) {
cm->max++;
cd = &cm->cd[cm->max];
} else {
struct colordesc *newCd;
/*
* Oops, must allocate more.
*/
n = cm->ncds * 2;
if (cm->cd == cm->cdspace) {
newCd = (struct colordesc *) MALLOC(n * sizeof(struct colordesc));
if (newCd != NULL) {
memcpy(newCd, cm->cdspace,
cm->ncds * sizeof(struct colordesc));
}
} else {
newCd = (struct colordesc *)
REALLOC(cm->cd, n * sizeof(struct colordesc));
}
if (newCd == NULL) {
CERR(OB_REG_ESPACE);
return COLORLESS;
}
cm->cd = newCd;
cm->ncds = n;
assert(cm->max < cm->ncds - 1);
cm->max++;
cd = &cm->cd[cm->max];
}
cd->nchrs = 0;
cd->sub = NOSUB;
cd->arcs = NULL;
cd->flags = 0;
cd->block = NULL;
return (color) (cd - cm->cd);
}
/*
- freecolor - free a color (must have no arcs or subcolor)
^ static void freecolor(struct colormap *, pcolor);
*/
static void
freecolor(
struct colormap *cm,
pcolor co)
{
assert(co >= 0);
struct colordesc *cd = &cm->cd[co];
color pco, nco; /* for freelist scan */
assert(co >= 0);
if (co == WHITE) {
return;
}
assert(cd->arcs == NULL);
assert(cd->sub == NOSUB);
assert(cd->nchrs == 0);
cd->flags = FREECOL;
if (cd->block != NULL) {
FREE(cd->block);
cd->block = NULL; /* just paranoia */
}
if ((size_t) co == cm->max) {
while (cm->max > WHITE && UNUSEDCOLOR(&cm->cd[cm->max])) {
cm->max--;
}
assert(cm->free >= 0);
while ((size_t) cm->free > cm->max) {
cm->free = cm->cd[cm->free].sub;
}
if (cm->free > 0) {
assert(cm->free < cm->max);
pco = cm->free;
nco = cm->cd[pco].sub;
while (nco > 0) {
if ((size_t) nco > cm->max) {
/*
* Take this one out of freelist.
*/
nco = cm->cd[nco].sub;
cm->cd[pco].sub = nco;
} else {
assert(nco < cm->max);
pco = nco;
nco = cm->cd[pco].sub;
}
}
}
} else {
cd->sub = cm->free;
cm->free = (color) (cd - cm->cd);
}
}
/*
- pseudocolor - allocate a false color, to be managed by other means
^ static color pseudocolor(struct colormap *);
*/
static color
pseudocolor(
struct colormap *cm)
{
color co;
co = newcolor(cm);
if (CISERR()) {
return COLORLESS;
}
assert(co >= 0);
cm->cd[co].nchrs = 1;
cm->cd[co].flags = PSEUDO;
return co;
}
/*
- subcolor - allocate a new subcolor (if necessary) to this chr
^ static color subcolor(struct colormap *, pchr c);
*/
static color
subcolor(
struct colormap *cm,
pchr c)
{
color co; /* current color of c */
color sco; /* new subcolor */
assert(c >= 0);
co = GETCOLOR(cm, c);
sco = newsub(cm, co);
if (CISERR()) {
return COLORLESS;
}
assert(sco != COLORLESS);
if (co == sco) { /* already in an open subcolor */
return co; /* rest is redundant */
}
assert(co >= 0 && sco >= 0);
cm->cd[co].nchrs--;
cm->cd[sco].nchrs++;
setcolor(cm, c, sco);
return sco;
}
/*
- newsub - allocate a new subcolor (if necessary) for a color
^ static color newsub(struct colormap *, pcolor);
*/
static color
newsub(
struct colormap *cm,
pcolor co)
{
color sco; /* new subcolor */
assert(co >= 0);
sco = cm->cd[co].sub;
if (sco == NOSUB) { /* color has no open subcolor */
if (cm->cd[co].nchrs == 1) { /* optimization */
return co;
}
sco = newcolor(cm); /* must create subcolor */
if (sco == COLORLESS) {
assert(CISERR());
return COLORLESS;
}
assert(co >= 0 && sco >= 0);
cm->cd[co].sub = sco;
cm->cd[sco].sub = sco; /* open subcolor points to self */
}
assert(sco != NOSUB);
return sco;
}
/*
- subrange - allocate new subcolors to this range of chrs, fill in arcs
^ static void subrange(struct vars *, pchr, pchr, struct state *,
^ struct state *);
*/
static void
subrange(
struct vars *v,
pchr from,
pchr to,
struct state *lp,
struct state *rp)
{
uchr uf;
int i;
assert(from <= to);
/*
* First, align "from" on a tree-block boundary
*/
uf = (uchr) from;
i = (int) (((uf + BYTTAB - 1) & (uchr) ~BYTMASK) - uf);
for (; from<=to && i>0; i--, from++) {
newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp);
}
if (from > to) { /* didn't reach a boundary */
return;
}
/*
* Deal with whole blocks.
*/
for (; to-from>=BYTTAB ; from+=BYTTAB) {
subblock(v, from, lp, rp);
}
/*
* Clean up any remaining partial table.
*/
for (; from<=to ; from++) {
newarc(v->nfa, PLAIN, subcolor(v->cm, from), lp, rp);
}
}
/*
- subblock - allocate new subcolors for one tree block of chrs, fill in arcs
^ static void subblock(struct vars *, pchr, struct state *, struct state *);
*/
static void
subblock(
struct vars *v,
pchr start, /* first of BYTTAB chrs */
struct state *lp,
struct state *rp)
{
uchr uc = start;
struct colormap *cm = v->cm;
int shift;
int level;
int i;
int b;
union tree *t;
union tree *cb;
union tree *fillt;
union tree *lastt;
int previ;
int ndone;
color co;
color sco;
assert((uc % BYTTAB) == 0);
/*
* Find its color block, making new pointer blocks as needed.
*/
t = cm->tree;
fillt = NULL;
for (level=0, shift=BYTBITS*(NBYTS-1); shift>0; level++, shift-=BYTBITS) {
b = (uc >> shift) & BYTMASK;
lastt = t;
t = lastt->tptr[b];
assert(t != NULL);
fillt = &cm->tree[level+1];
if (t == fillt && shift > BYTBITS) { /* need new ptr block */
t = (union tree *) MALLOC(sizeof(struct ptrs));
if (t == NULL) {
CERR(OB_REG_ESPACE);
return;
}
memcpy(t->tptr, fillt->tptr, BYTTAB*sizeof(union tree *));
lastt->tptr[b] = t;
}
}
/*
* Special cases: fill block or solid block.
*/
co = t->tcolor[0];
assert(co >= 0);
cb = cm->cd[co].block;
if (t == fillt || t == cb) {
/*
* Either way, we want a subcolor solid block.
*/
sco = newsub(cm, co);
assert(sco >= 0);
t = cm->cd[sco].block;
if (t == NULL) { /* must set it up */
t = (union tree *) MALLOC(sizeof(struct colors));
if (t == NULL) {
CERR(OB_REG_ESPACE);
return;
}
for (i=0 ; i<BYTTAB ; i++) {
t->tcolor[i] = sco;
}
cm->cd[sco].block = t;
}
/*
* Find loop must have run at least once.
*/
lastt->tptr[b] = t;
newarc(v->nfa, PLAIN, sco, lp, rp);
assert(sco >= 0 && co >= 0);
cm->cd[co].nchrs -= BYTTAB;
cm->cd[sco].nchrs += BYTTAB;
return;
}
/*
* General case, a mixed block to be altered.
*/
i = 0;
while (i < BYTTAB) {
co = t->tcolor[i];
sco = newsub(cm, co);
newarc(v->nfa, PLAIN, sco, lp, rp);
previ = i;
do {
t->tcolor[i++] = sco;
} while (i < BYTTAB && t->tcolor[i] == co);
ndone = i - previ;
assert(sco >= 0 && co >= 0);
cm->cd[co].nchrs -= ndone;
cm->cd[sco].nchrs += ndone;
}
}
/*
- okcolors - promote subcolors to full colors
^ static void okcolors(struct nfa *, struct colormap *);
*/
static void
okcolors(
struct nfa *nfa,
struct colormap *cm)
{
struct colordesc *cd;
struct colordesc *end = CDEND(cm);
struct colordesc *scd;
struct arc *a;
color co;
color sco;
for (cd=cm->cd, co=0 ; cd<end ; cd++, co++) {
sco = cd->sub;
if (UNUSEDCOLOR(cd) || sco == NOSUB) {
/*
* Has no subcolor, no further action.
*/
} else if (sco == co) {
/*
* Is subcolor, let parent deal with it.
*/
} else if (cd->nchrs == 0) {
/*
* Parent empty, its arcs change color to subcolor.
*/
assert(sco >= 0);
cd->sub = NOSUB;
scd = &cm->cd[sco];
assert(scd->nchrs > 0);
assert(scd->sub == sco);
scd->sub = NOSUB;
while ((a = cd->arcs) != NULL) {
assert(a->co == co);
uncolorchain(cm, a);
a->co = sco;
colorchain(cm, a);
}
freecolor(cm, co);
} else {
/*
* Parent's arcs must gain parallel subcolor arcs.
*/
assert(sco >= 0);
cd->sub = NOSUB;
scd = &cm->cd[sco];
assert(scd->nchrs > 0);
assert(scd->sub == sco);
scd->sub = NOSUB;
for (a=cd->arcs ; a!=NULL ; a=a->colorchain) {
assert(a->co == co);
newarc(nfa, a->type, sco, a->from, a->to);
}
}
}
}
/*
- colorchain - add this arc to the color chain of its color
^ static void colorchain(struct colormap *, struct arc *);
*/
static void
colorchain(
struct colormap *cm,
struct arc *a)
{
struct colordesc *cd = &cm->cd[a->co];
if (cd->arcs != NULL) {
cd->arcs->colorchainRev = a;
}
a->colorchain = cd->arcs;
a->colorchainRev = NULL;
cd->arcs = a;
}
/*
- uncolorchain - delete this arc from the color chain of its color
^ static void uncolorchain(struct colormap *, struct arc *);
*/
static void
uncolorchain(
struct colormap *cm,
struct arc *a)
{
struct colordesc *cd = &cm->cd[a->co];
struct arc *aa = a->colorchainRev;
if (aa == NULL) {
assert(cd->arcs == a);
cd->arcs = a->colorchain;
} else {
assert(aa->colorchain == a);
aa->colorchain = a->colorchain;
}
if (a->colorchain != NULL) {
a->colorchain->colorchainRev = aa;
}
a->colorchain = NULL; /* paranoia */
a->colorchainRev = NULL;
}
/*
- rainbow - add arcs of all full colors (but one) between specified states
^ static void rainbow(struct nfa *, struct colormap *, int, pcolor,
^ struct state *, struct state *);
*/
static void
rainbow(
struct nfa *nfa,
struct colormap *cm,
int type,
pcolor but, /* COLORLESS if no exceptions */
struct state *from,
struct state *to)
{
struct colordesc *cd;
struct colordesc *end = CDEND(cm);
color co;
for (cd=cm->cd, co=0 ; cd<end && !CISERR(); cd++, co++) {
if (!UNUSEDCOLOR(cd) && (cd->sub != co) && (co != but)
&& !(cd->flags&PSEUDO)) {
newarc(nfa, type, co, from, to);
}
}
}
/*
- colorcomplement - add arcs of complementary colors
* The calling sequence ought to be reconciled with cloneouts().
^ static void colorcomplement(struct nfa *, struct colormap *, int,
^ struct state *, struct state *, struct state *);
*/
static void
colorcomplement(
struct nfa *nfa,
struct colormap *cm,
int type,
struct state *of, /* complements of this guy's PLAIN outarcs */
struct state *from,
struct state *to)
{
struct colordesc *cd;
struct colordesc *end = CDEND(cm);
color co;
assert(of != from);
for (cd=cm->cd, co=0 ; cd<end && !CISERR() ; cd++, co++) {
if (!UNUSEDCOLOR(cd) && !(cd->flags&PSEUDO)) {
if (findarc(of, PLAIN, co) == NULL) {
newarc(nfa, type, co, from, to);
}
}
}
}
#ifdef OB_REG_DEBUG
/*
^ #ifdef OB_REG_DEBUG
*/
/*
- dumpcolors - debugging output
^ static void dumpcolors(struct colormap *, FILE *);
*/
static void
dumpcolors(
struct colormap *cm,
FILE *f)
{
struct colordesc *cd;
struct colordesc *end;
color co;
chr c;
char *has;
fprintf(f, "max %ld\n", (long) cm->max);
if (NBYTS > 1) {
fillcheck(cm, cm->tree, 0, f);
}
end = CDEND(cm);
for (cd=cm->cd+1, co=1 ; cd<end ; cd++, co++) { /* skip 0 */
if (!UNUSEDCOLOR(cd)) {
assert(cd->nchrs > 0);
has = (cd->block != NULL) ? "#" : "";
if (cd->flags&PSEUDO) {
fprintf(f, "#%2ld%s(ps): ", (long) co, has);
} else {
fprintf(f, "#%2ld%s(%2d): ", (long) co, has, cd->nchrs);
}
/*
* It's hard to do this more efficiently.
*/
for (c=CHR_MIN ; c<CHR_MAX ; c++) {
if (GETCOLOR(cm, c) == co) {
dumpchr(c, f);
}
}
assert(c == CHR_MAX);
if (GETCOLOR(cm, c) == co) {
dumpchr(c, f);
}
fprintf(f, "\n");
}
}
}
/*
- fillcheck - check proper filling of a tree
^ static void fillcheck(struct colormap *, union tree *, int, FILE *);
*/
static void
fillcheck(
struct colormap *cm,
union tree *tree,
int level, /* level number (top == 0) of this block */
FILE *f)
{
int i;
union tree *t;
union tree *fillt = &cm->tree[level+1];
assert(level < NBYTS-1); /* this level has pointers */
for (i=BYTTAB-1 ; i>=0 ; i--) {
t = tree->tptr[i];
if (t == NULL) {
fprintf(f, "NULL found in filled tree!\n");
} else if (t == fillt) {
/* empty body */
} else if (level < NBYTS-2) { /* more pointer blocks below */
fillcheck(cm, t, level+1, f);
}
}
}
/*
- dumpchr - print a chr
* Kind of char-centric but works well enough for debug use.
^ static void dumpchr(pchr, FILE *);
*/
static void
dumpchr(
pchr c,
FILE *f)
{
if (c == '\\') {
fprintf(f, "\\\\");
} else if (c > ' ' && c <= '~') {
putc((char) c, f);
} else {
fprintf(f, "\\u%04lx", (long) c);
}
}
/*
^ #endif
*/
#endif /* ifdef OB_REG_DEBUG */
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

View File

@ -1,146 +0,0 @@
/*
* Utility functions for handling cvecs
* This file is #included by regcomp.c.
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Notes:
* Only (selected) functions in _this_ file should treat chr* as non-constant.
*/
/*
- newcvec - allocate a new cvec
^ static struct cvec *newcvec(int, int);
*/
static struct cvec *
newcvec(
int nchrs, /* to hold this many chrs... */
int nranges) /* ... and this many ranges... */
{
size_t nc = (size_t)nchrs + (size_t)nranges*2;
size_t n = sizeof(struct cvec) + nc*sizeof(chr);
struct cvec *cv = (struct cvec *) MALLOC(n);
if (cv == NULL) {
return NULL;
}
cv->chrspace = nchrs;
cv->chrs = (chr *)(((char *)cv)+sizeof(struct cvec));
cv->ranges = cv->chrs + nchrs;
cv->rangespace = nranges;
return clearcvec(cv);
}
/*
- clearcvec - clear a possibly-new cvec
* Returns pointer as convenience.
^ static struct cvec *clearcvec(struct cvec *);
*/
static struct cvec *
clearcvec(
struct cvec *cv) /* character vector */
{
assert(cv != NULL);
cv->nchrs = 0;
cv->nranges = 0;
return cv;
}
/*
- addchr - add a chr to a cvec
^ static void addchr(struct cvec *, pchr);
*/
static void
addchr(
struct cvec *cv, /* character vector */
pchr c) /* character to add */
{
cv->chrs[cv->nchrs++] = (chr)c;
}
/*
- addrange - add a range to a cvec
^ static void addrange(struct cvec *, pchr, pchr);
*/
static void
addrange(
struct cvec *cv, /* character vector */
pchr from, /* first character of range */
pchr to) /* last character of range */
{
assert(cv->nranges < cv->rangespace);
cv->ranges[cv->nranges*2] = (chr)from;
cv->ranges[cv->nranges*2 + 1] = (chr)to;
cv->nranges++;
}
/*
- getcvec - get a cvec, remembering it as v->cv
^ static struct cvec *getcvec(struct vars *, int, int);
*/
static struct cvec *
getcvec(
struct vars *v, /* context */
int nchrs, /* to hold this many chrs... */
int nranges) /* ... and this many ranges... */
{
if ((v->cv != NULL) && (nchrs <= v->cv->chrspace) &&
(nranges <= v->cv->rangespace)) {
return clearcvec(v->cv);
}
if (v->cv != NULL) {
freecvec(v->cv);
}
v->cv = newcvec(nchrs, nranges);
if (v->cv == NULL) {
ERR(OB_REG_ESPACE);
}
return v->cv;
}
/*
- freecvec - free a cvec
^ static void freecvec(struct cvec *);
*/
static void
freecvec(
struct cvec *cv) /* character vector */
{
FREE(cv);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,185 +0,0 @@
/*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms - with or without
* modification - are permitted for any purpose, provided that redistributions
* in source form retain this entire copyright notice and indicate the origin
* and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Headers if any.
*/
#ifdef REGEX_STANDALONE
# include "regalone.h"
//#else
//# include "obInt.h"
#endif
/*
* Overrides for regguts.h definitions, if any.
*/
#define FUNCPTR(name, args) (*name)args
#ifndef REGEX_STANDALONE
#define MALLOC(n) ckalloc(n)
#define FREE(p) ckfree(VS(p))
#define REALLOC(p,n) ckrealloc(VS(p),n)
#endif
/*
* Do not insert extras between the "begin" and "end" lines - this chunk is
* automatically extracted to be fitted into regex.h.
*/
/* --- begin --- */
/* Ensure certain things don't sneak in from system headers. */
#ifdef __REG_WIDE_T
#undef __REG_WIDE_T
#endif
#ifdef __REG_WIDE_COMPILE
#undef __REG_WIDE_COMPILE
#endif
#ifdef __REG_WIDE_EXEC
#undef __REG_WIDE_EXEC
#endif
#ifdef __REG_REGOFF_T
#undef __REG_REGOFF_T
#endif
#ifdef __REG_VOID_T
#undef __REG_VOID_T
#endif
#ifdef __REG_CONST
#undef __REG_CONST
#endif
#ifdef __REG_NOFRONT
#undef __REG_NOFRONT
#endif
#ifdef __REG_NOCHAR
#undef __REG_NOCHAR
#endif
/* Interface types */
#define __REG_WIDE_T Ob_UniChar
#define __REG_REGOFF_T long /* Not really right, but good enough... */
#define __REG_VOID_T void
#define __REG_CONST const
/* Names and declarations */
#define __REG_WIDE_COMPILE ObReComp
#define __REG_WIDE_EXEC ObReExec
#define __REG_NOFRONT /* Don't want ob_regcomp() and ob_regexec() */
#define __REG_NOCHAR /* Or the char versions */
#define ob_regfree ObReFree
#define ob_regerror ObReError
/* --- end --- */
/*
* Internal character type and related.
*/
#ifndef REGEX_STANDALONE
typedef Ob_UniChar chr; /* The type itself. */
#endif
typedef int pchr; /* What it promotes to. */
typedef unsigned uchr; /* Unsigned type that will hold a chr. */
typedef int celt; /* Type to hold chr, or NOCELT */
#define NOCELT (-1) /* Celt value which is not valid chr */
#define CHR(c) (UCHAR(c)) /* Turn char literal into chr literal */
#define DIGITVAL(c) ((c)-'0') /* Turn chr digit into its value */
#if OB_UTF_MAX > 3
#define CHRBITS 32 /* Bits in a chr; must not use sizeof */
#define CHR_MIN 0x00000000 /* Smallest and largest chr; the value */
#define CHR_MAX 0xffffffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */
#elif defined(REGEX_STANDALONE) && ! defined(REGEX_WCHAR)
# define CHRBITS 8
# define CHR_MIN 0x00
# define CHR_MAX 0xff
#else
#define CHRBITS 16 /* Bits in a chr; must not use sizeof */
#define CHR_MIN 0x0000 /* Smallest and largest chr; the value */
#define CHR_MAX 0xffff /* CHR_MAX-CHR_MIN+1 should fit in uchr */
#endif
/*
* Functions operating on chr.
*/
#define iscalnum(x) Ob_UniCharIsAlnum(x)
#define iscalpha(x) Ob_UniCharIsAlpha(x)
#define iscdigit(x) Ob_UniCharIsDigit(x)
#define iscspace(x) Ob_UniCharIsSpace(x)
/*
* Name the external functions.
*/
#ifdef REGEX_STANDALONE
# ifdef REGEX_WCHAR
# define compile ob_re_wcomp
# define exec ob_re_wexec
# define __REG_NOCHAR
# else
# define compile ob_re_comp
# define exec ob_re_exec
# undef __REG_NOCHAR
# endif
#else
#define compile ObReComp
#define exec ObReExec
#endif
/*
& Enable/disable debugging code (by whether OB_REG_DEBUG is defined or not).
*/
#if 0 /* No debug unless requested by makefile. */
#define OB_REG_DEBUG /* */
#endif
#ifndef REGEX_STANDALONE
/*
* Method of allocating a local workspace. We used a thread-specific data
* space to store this because the regular expression engine is never
* reentered from the same thread; it doesn't make any callbacks.
*/
#define AllocVars(vPtr) \
static Ob_ThreadDataKey varsKey; \
register struct vars *vPtr = (struct vars *) \
Ob_GetThreadData(&varsKey, sizeof(struct vars))
#elif 0
/*
* This strategy for allocating workspace is "more proper" in some sense, but
* quite a bit slower. Using TSD (as above) leads to code that is quite a bit
* faster in practice (measured!)
*/
#define AllocVars(vPtr) \
register struct vars *vPtr = (struct vars *) MALLOC(sizeof(struct vars))
#define FreeVars(vPtr) \
FREE(vPtr)
#endif
/*
* And pick up the standard header.
*/
#include "ob_regex.h"

View File

@ -1,818 +0,0 @@
/*
* DFA routines
* This file is #included by regexec.c.
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation
* of software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
- longest - longest-preferred matching engine
^ static chr *longest(struct vars *, struct dfa *, chr *, chr *, int *);
*/
static chr * /* endpoint, or NULL */
longest(
struct vars *v, /* used only for debug and exec flags */
struct dfa *d,
chr *start, /* where the match should start */
chr *stop, /* match must end at or before here */
int *hitstopp) /* record whether hit v->stop, if non-NULL */
{
chr *cp;
chr *realstop = (stop == v->stop) ? stop : stop + 1;
color co;
struct sset *css;
struct sset *ss;
chr *post;
int i;
struct colormap *cm = d->cm;
/*
* Initialize.
*/
css = initialize(v, d, start);
cp = start;
if (hitstopp != NULL) {
*hitstopp = 0;
}
/*
* Startup.
*/
FDEBUG(("+++ startup +++\n"));
if (cp == v->start) {
co = d->cnfa->bos[(v->eflags&OB_REG_NOTBOL) ? 0 : 1];
FDEBUG(("color %ld\n", (long)co));
} else {
co = GETCOLOR(cm, *(cp - 1));
FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co));
}
css = miss(v, d, css, co, cp, start);
if (css == NULL) {
return NULL;
}
css->lastseen = cp;
/*
* Main loop.
*/
if (v->eflags&OB_REG_FTRACE) {
while (cp < realstop) {
FDEBUG(("+++ at c%d +++\n", css - d->ssets));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
if (ss == NULL) {
ss = miss(v, d, css, co, cp+1, start);
if (ss == NULL) {
break; /* NOTE BREAK OUT */
}
}
cp++;
ss->lastseen = cp;
css = ss;
}
} else {
while (cp < realstop) {
co = GETCOLOR(cm, *cp);
ss = css->outs[co];
if (ss == NULL) {
ss = miss(v, d, css, co, cp+1, start);
if (ss == NULL) {
break; /* NOTE BREAK OUT */
}
}
cp++;
ss->lastseen = cp;
css = ss;
}
}
/*
* Shutdown.
*/
FDEBUG(("+++ shutdown at c%d +++\n", css - d->ssets));
if (cp == v->stop && stop == v->stop) {
if (hitstopp != NULL) {
*hitstopp = 1;
}
co = d->cnfa->eos[(v->eflags&OB_REG_NOTEOL) ? 0 : 1];
FDEBUG(("color %ld\n", (long)co));
ss = miss(v, d, css, co, cp, start);
/*
* Special case: match ended at eol?
*/
if (ss != NULL && (ss->flags&POSTSTATE)) {
return cp;
} else if (ss != NULL) {
ss->lastseen = cp; /* to be tidy */
}
}
/*
* Find last match, if any.
*/
post = d->lastpost;
for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) {
if ((ss->flags&POSTSTATE) && (post != ss->lastseen) &&
(post == NULL || post < ss->lastseen)) {
post = ss->lastseen;
}
}
if (post != NULL) { /* found one */
return post - 1;
}
return NULL;
}
/*
- shortest - shortest-preferred matching engine
^ static chr *shortest(struct vars *, struct dfa *, chr *, chr *, chr *,
^ chr **, int *);
*/
static chr * /* endpoint, or NULL */
shortest(
struct vars *v,
struct dfa *d,
chr *start, /* where the match should start */
chr *min, /* match must end at or after here */
chr *max, /* match must end at or before here */
chr **coldp, /* store coldstart pointer here, if nonNULL */
int *hitstopp) /* record whether hit v->stop, if non-NULL */
{
chr *cp;
chr *realmin = (min == v->stop) ? min : min + 1;
chr *realmax = (max == v->stop) ? max : max + 1;
color co;
struct sset *css;
struct sset *ss;
struct colormap *cm = d->cm;
/*
* Initialize.
*/
css = initialize(v, d, start);
cp = start;
if (hitstopp != NULL) {
*hitstopp = 0;
}
/*
* Startup.
*/
FDEBUG(("--- startup ---\n"));
if (cp == v->start) {
co = d->cnfa->bos[(v->eflags&OB_REG_NOTBOL) ? 0 : 1];
FDEBUG(("color %ld\n", (long)co));
} else {
co = GETCOLOR(cm, *(cp - 1));
FDEBUG(("char %c, color %ld\n", (char)*(cp-1), (long)co));
}
css = miss(v, d, css, co, cp, start);
if (css == NULL) {
return NULL;
}
css->lastseen = cp;
ss = css;
/*
* Main loop.
*/
if (v->eflags&OB_REG_FTRACE) {
while (cp < realmax) {
FDEBUG(("--- at c%d ---\n", css - d->ssets));
co = GETCOLOR(cm, *cp);
FDEBUG(("char %c, color %ld\n", (char)*cp, (long)co));
ss = css->outs[co];
if (ss == NULL) {
ss = miss(v, d, css, co, cp+1, start);
if (ss == NULL) {
break; /* NOTE BREAK OUT */
}
}
cp++;
ss->lastseen = cp;
css = ss;
if ((ss->flags&POSTSTATE) && cp >= realmin) {
break; /* NOTE BREAK OUT */
}
}
} else {
while (cp < realmax) {
co = GETCOLOR(cm, *cp);
ss = css->outs[co];
if (ss == NULL) {
ss = miss(v, d, css, co, cp+1, start);
if (ss == NULL) {
break; /* NOTE BREAK OUT */
}
}
cp++;
ss->lastseen = cp;
css = ss;
if ((ss->flags&POSTSTATE) && cp >= realmin) {
break; /* NOTE BREAK OUT */
}
}
}
if (ss == NULL) {
return NULL;
}
if (coldp != NULL) { /* report last no-progress state set, if any */
*coldp = lastcold(v, d);
}
if ((ss->flags&POSTSTATE) && cp > min) {
assert(cp >= realmin);
cp--;
} else if (cp == v->stop && max == v->stop) {
co = d->cnfa->eos[(v->eflags&OB_REG_NOTEOL) ? 0 : 1];
FDEBUG(("color %ld\n", (long)co));
ss = miss(v, d, css, co, cp, start);
/*
* Match might have ended at eol.
*/
if ((ss == NULL || !(ss->flags&POSTSTATE)) && hitstopp != NULL) {
*hitstopp = 1;
}
}
if (ss == NULL || !(ss->flags&POSTSTATE)) {
return NULL;
}
return cp;
}
/*
- lastcold - determine last point at which no progress had been made
^ static chr *lastcold(struct vars *, struct dfa *);
*/
static chr * /* endpoint, or NULL */
lastcold(
struct vars *v,
struct dfa *d)
{
struct sset *ss;
chr *nopr;
int i;
nopr = d->lastnopr;
if (nopr == NULL) {
nopr = v->start;
}
for (ss = d->ssets, i = d->nssused; i > 0; ss++, i--) {
if ((ss->flags&NOPROGRESS) && nopr < ss->lastseen) {
nopr = ss->lastseen;
}
}
return nopr;
}
/*
- newdfa - set up a fresh DFA
^ static struct dfa *newdfa(struct vars *, struct cnfa *,
^ struct colormap *, struct smalldfa *);
*/
static struct dfa *
newdfa(
struct vars *v,
struct cnfa *cnfa,
struct colormap *cm,
struct smalldfa *small) /* preallocated space, may be NULL */
{
struct dfa *d = NULL;
size_t nss = cnfa->nstates * 2;
int wordsper = (cnfa->nstates + UBITS - 1) / UBITS;
struct smalldfa *smallwas = small;
assert(cnfa != NULL && cnfa->nstates != 0);
if (nss <= FEWSTATES && cnfa->ncolors <= FEWCOLORS) {
assert(wordsper == 1);
if (small == NULL) {
small = (struct smalldfa *) MALLOC(sizeof(struct smalldfa));
if (small == NULL) {
ERR(OB_REG_ESPACE);
return NULL;
}
}
d = &small->dfa;
d->ssets = small->ssets;
d->statesarea = small->statesarea;
d->work = &d->statesarea[nss];
d->outsarea = small->outsarea;
d->incarea = small->incarea;
d->cptsmalloced = 0;
d->mallocarea = (smallwas == NULL) ? (char *)small : NULL;
} else {
d = (struct dfa *)MALLOC(sizeof(struct dfa));
if (d == NULL) {
ERR(OB_REG_ESPACE);
return NULL;
}
d->ssets = (struct sset *)MALLOC(nss * sizeof(struct sset));
d->statesarea = (unsigned *)
MALLOC((nss+WORK) * wordsper * sizeof(unsigned));
d->work = &d->statesarea[nss * wordsper];
d->outsarea = (struct sset **)
MALLOC(nss * cnfa->ncolors * sizeof(struct sset *));
d->incarea = (struct arcp *)
MALLOC(nss * cnfa->ncolors * sizeof(struct arcp));
d->cptsmalloced = 1;
d->mallocarea = (char *)d;
if (d->ssets == NULL || d->statesarea == NULL ||
d->outsarea == NULL || d->incarea == NULL) {
freedfa(d);
ERR(OB_REG_ESPACE);
return NULL;
}
}
d->nssets = (v->eflags&OB_REG_SMALL) ? 7 : nss;
d->nssused = 0;
d->nstates = cnfa->nstates;
d->ncolors = cnfa->ncolors;
d->wordsper = wordsper;
d->cnfa = cnfa;
d->cm = cm;
d->lastpost = NULL;
d->lastnopr = NULL;
d->search = d->ssets;
/*
* Initialization of sset fields is done as needed.
*/
return d;
}
/*
- freedfa - free a DFA
^ static void freedfa(struct dfa *);
*/
static void
freedfa(
struct dfa *d)
{
if (d != NULL) {
if (d->cptsmalloced) {
if (d->ssets != NULL) {
FREE(d->ssets);
}
if (d->statesarea != NULL) {
FREE(d->statesarea);
}
if (d->outsarea != NULL) {
FREE(d->outsarea);
}
if (d->incarea != NULL) {
FREE(d->incarea);
}
}
if (d->mallocarea != NULL) {
FREE(d->mallocarea);
}
}
}
/*
- hash - construct a hash code for a bitvector
* There are probably better ways, but they're more expensive.
^ static unsigned hash(unsigned *, int);
*/
static unsigned
hash(
unsigned *uv,
int n)
{
int i;
unsigned h;
h = 0;
for (i = 0; i < n; i++) {
h ^= uv[i];
}
return h;
}
/*
- initialize - hand-craft a cache entry for startup, otherwise get ready
^ static struct sset *initialize(struct vars *, struct dfa *, chr *);
*/
static struct sset *
initialize(
struct vars *v, /* used only for debug flags */
struct dfa *d,
chr *start)
{
struct sset *ss;
int i;
/*
* Is previous one still there?
*/
if (d->nssused > 0 && (d->ssets[0].flags&STARTER)) {
ss = &d->ssets[0];
} else { /* no, must (re)build it */
ss = getvacant(v, d, start, start);
for (i = 0; i < d->wordsper; i++) {
ss->states[i] = 0;
}
BSET(ss->states, d->cnfa->pre);
ss->hash = HASH(ss->states, d->wordsper);
assert(d->cnfa->pre != d->cnfa->post);
ss->flags = STARTER|LOCKED|NOPROGRESS;
/*
* lastseen dealt with below
*/
}
for (i = 0; i < d->nssused; i++) {
d->ssets[i].lastseen = NULL;
}
ss->lastseen = start; /* maybe untrue, but harmless */
d->lastpost = NULL;
d->lastnopr = NULL;
return ss;
}
/*
- miss - handle a cache miss
^ static struct sset *miss(struct vars *, struct dfa *, struct sset *,
^ pcolor, chr *, chr *);
*/
static struct sset * /* NULL if goes to empty set */
miss(
struct vars *v, /* used only for debug flags */
struct dfa *d,
struct sset *css,
pcolor co,
chr *cp, /* next chr */
chr *start) /* where the attempt got started */
{
struct cnfa *cnfa = d->cnfa;
int i;
unsigned h;
struct carc *ca;
struct sset *p;
int ispost;
int noprogress;
int gotstate;
int dolacons;
int sawlacons;
/*
* For convenience, we can be called even if it might not be a miss.
*/
if (css->outs[co] != NULL) {
FDEBUG(("hit\n"));
return css->outs[co];
}
FDEBUG(("miss\n"));
/*
* First, what set of states would we end up in?
*/
for (i = 0; i < d->wordsper; i++) {
d->work[i] = 0;
}
ispost = 0;
noprogress = 1;
gotstate = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(css->states, i)) {
for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
if (ca->co == co) {
BSET(d->work, ca->to);
gotstate = 1;
if (ca->to == cnfa->post) {
ispost = 1;
}
if (!cnfa->states[ca->to]->co) {
noprogress = 0;
}
FDEBUG(("%d -> %d\n", i, ca->to));
}
}
}
}
dolacons = (gotstate) ? (cnfa->flags&HASLACONS) : 0;
sawlacons = 0;
while (dolacons) { /* transitive closure */
dolacons = 0;
for (i = 0; i < d->nstates; i++) {
if (ISBSET(d->work, i)) {
for (ca = cnfa->states[i]+1; ca->co != COLORLESS; ca++) {
if (ca->co <= cnfa->ncolors) {
continue; /* NOTE CONTINUE */
}
sawlacons = 1;
if (ISBSET(d->work, ca->to)) {
continue; /* NOTE CONTINUE */
}
if (!lacon(v, cnfa, cp, ca->co)) {
continue; /* NOTE CONTINUE */
}
BSET(d->work, ca->to);
dolacons = 1;
if (ca->to == cnfa->post) {
ispost = 1;
}
if (!cnfa->states[ca->to]->co) {
noprogress = 0;
}
FDEBUG(("%d :> %d\n", i, ca->to));
}
}
}
}
if (!gotstate) {
return NULL;
}
h = HASH(d->work, d->wordsper);
/*
* Next, is that in the cache?
*/
for (p = d->ssets, i = d->nssused; i > 0; p++, i--) {
if (HIT(h, d->work, p, d->wordsper)) {
FDEBUG(("cached c%d\n", p - d->ssets));
break; /* NOTE BREAK OUT */
}
}
if (i == 0) { /* nope, need a new cache entry */
p = getvacant(v, d, cp, start);
assert(p != css);
for (i = 0; i < d->wordsper; i++) {
p->states[i] = d->work[i];
}
p->hash = h;
p->flags = (ispost) ? POSTSTATE : 0;
if (noprogress) {
p->flags |= NOPROGRESS;
}
/*
* lastseen to be dealt with by caller
*/
}
if (!sawlacons) { /* lookahead conds. always cache miss */
FDEBUG(("c%d[%d]->c%d\n", css - d->ssets, co, p - d->ssets));
css->outs[co] = p;
css->inchain[co] = p->ins;
p->ins.ss = css;
p->ins.co = (color)co;
}
return p;
}
/*
- lacon - lookahead-constraint checker for miss()
^ static int lacon(struct vars *, struct cnfa *, chr *, pcolor);
*/
static int /* predicate: constraint satisfied? */
lacon(
struct vars *v,
struct cnfa *pcnfa, /* parent cnfa */
chr *cp,
pcolor co) /* "color" of the lookahead constraint */
{
int n;
struct subre *sub;
struct dfa *d;
struct smalldfa sd;
chr *end;
n = co - pcnfa->ncolors;
assert(n < v->g->nlacons && v->g->lacons != NULL);
FDEBUG(("=== testing lacon %d\n", n));
sub = &v->g->lacons[n];
d = newdfa(v, &sub->cnfa, &v->g->cmap, &sd);
if (d == NULL) {
ERR(OB_REG_ESPACE);
return 0;
}
end = longest(v, d, cp, v->stop, (int *)NULL);
freedfa(d);
FDEBUG(("=== lacon %d match %d\n", n, (end != NULL)));
return (sub->subno) ? (end != NULL) : (end == NULL);
}
/*
- getvacant - get a vacant state set
* This routine clears out the inarcs and outarcs, but does not otherwise
* clear the innards of the state set -- that's up to the caller.
^ static struct sset *getvacant(struct vars *, struct dfa *, chr *, chr *);
*/
static struct sset *
getvacant(
struct vars *v, /* used only for debug flags */
struct dfa *d,
chr *cp,
chr *start)
{
int i;
struct sset *ss;
struct sset *p;
struct arcp ap;
struct arcp lastap = {NULL, 0}; /* silence gcc 4 warning */
color co;
ss = pickss(v, d, cp, start);
assert(!(ss->flags&LOCKED));
/*
* Clear out its inarcs, including self-referential ones.
*/
ap = ss->ins;
while ((p = ap.ss) != NULL) {
co = ap.co;
FDEBUG(("zapping c%d's %ld outarc\n", p - d->ssets, (long)co));
p->outs[co] = NULL;
ap = p->inchain[co];
p->inchain[co].ss = NULL; /* paranoia */
}
ss->ins.ss = NULL;
/*
* Take it off the inarc chains of the ssets reached by its outarcs.
*/
for (i = 0; i < d->ncolors; i++) {
p = ss->outs[i];
assert(p != ss); /* not self-referential */
if (p == NULL) {
continue; /* NOTE CONTINUE */
}
FDEBUG(("del outarc %d from c%d's in chn\n", i, p - d->ssets));
if (p->ins.ss == ss && p->ins.co == i) {
p->ins = ss->inchain[i];
} else {
assert(p->ins.ss != NULL);
for (ap = p->ins; ap.ss != NULL &&
!(ap.ss == ss && ap.co == i);
ap = ap.ss->inchain[ap.co]) {
lastap = ap;
}
assert(ap.ss != NULL);
lastap.ss->inchain[lastap.co] = ss->inchain[i];
}
ss->outs[i] = NULL;
ss->inchain[i].ss = NULL;
}
/*
* If ss was a success state, may need to remember location.
*/
if ((ss->flags&POSTSTATE) && ss->lastseen != d->lastpost &&
(d->lastpost == NULL || d->lastpost < ss->lastseen)) {
d->lastpost = ss->lastseen;
}
/*
* Likewise for a no-progress state.
*/
if ((ss->flags&NOPROGRESS) && ss->lastseen != d->lastnopr &&
(d->lastnopr == NULL || d->lastnopr < ss->lastseen)) {
d->lastnopr = ss->lastseen;
}
return ss;
}
/*
- pickss - pick the next stateset to be used
^ static struct sset *pickss(struct vars *, struct dfa *, chr *, chr *);
*/
static struct sset *
pickss(
struct vars *v, /* used only for debug flags */
struct dfa *d,
chr *cp,
chr *start)
{
int i;
struct sset *ss;
struct sset *end;
chr *ancient;
/*
* Shortcut for cases where cache isn't full.
*/
if (d->nssused < d->nssets) {
i = d->nssused;
d->nssused++;
ss = &d->ssets[i];
FDEBUG(("new c%d\n", i));
/*
* Set up innards.
*/
ss->states = &d->statesarea[i * d->wordsper];
ss->flags = 0;
ss->ins.ss = NULL;
ss->ins.co = WHITE; /* give it some value */
ss->outs = &d->outsarea[i * d->ncolors];
ss->inchain = &d->incarea[i * d->ncolors];
for (i = 0; i < d->ncolors; i++) {
ss->outs[i] = NULL;
ss->inchain[i].ss = NULL;
}
return ss;
}
/*
* Look for oldest, or old enough anyway.
*/
if (cp - start > d->nssets*2/3) { /* oldest 33% are expendable */
ancient = cp - d->nssets*2/3;
} else {
ancient = start;
}
for (ss = d->search, end = &d->ssets[d->nssets]; ss < end; ss++) {
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
FDEBUG(("replacing c%d\n", ss - d->ssets));
return ss;
}
}
for (ss = d->ssets, end = d->search; ss < end; ss++) {
if ((ss->lastseen == NULL || ss->lastseen < ancient)
&& !(ss->flags&LOCKED)) {
d->search = ss + 1;
FDEBUG(("replacing c%d\n", ss - d->ssets));
return ss;
}
}
/*
* Nobody's old enough?!? -- something's really wrong.
*/
FDEBUG(("can't find victim to replace!\n"));
assert(NOTREACHED);
ERR(OB_REG_ASSERT);
return d->ssets;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

View File

@ -1,131 +0,0 @@
/*
* ob_regerror - error-code expansion
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "regguts.h"
/*
* Unknown-error explanation.
*/
static char unk[] = "*** unknown regex error code 0x%x ***";
/*
* Struct to map among codes, code names, and explanations.
*/
static struct rerr {
int code;
const char *name;
const char *explain;
} rerrs[] = {
/* The actual table is built from regex.h */
#include "regerrs.h"
{ -1, "", "oops" }, /* explanation special-cased in code */
};
/*
- ob_regerror - the interface to error numbers
*/
/* ARGSUSED */
size_t /* Actual space needed (including NUL) */
ob_regerror(
int code, /* Error code, or REG_ATOI or REG_ITOA */
const ob_regex_t *preg, /* Associated ob_regex_t (unused at present) */
char *errbuf, /* Result buffer (unless errbuf_size==0) */
size_t errbuf_size) /* Available space in errbuf, can be 0 */
{
struct rerr *r;
const char *msg;
char convbuf[sizeof(unk)+50]; /* 50 = plenty for int */
size_t len;
int icode;
if (preg != NULL) {}
switch (code) {
case OB_REG_ATOI: /* Convert name to number */
for (r = rerrs; r->code >= 0; r++) {
if (strcmp(r->name, errbuf) == 0) {
break;
}
}
sprintf(convbuf, "%d", r->code); /* -1 for unknown */
msg = convbuf;
break;
case OB_REG_ITOA: /* Convert number to name */
icode = atoi(errbuf); /* Not our problem if this fails */
for (r = rerrs; r->code >= 0; r++) {
if (r->code == icode) {
break;
}
}
if (r->code >= 0) {
msg = r->name;
} else { /* Unknown; tell him the number */
sprintf(convbuf, "REG_%u", (unsigned)icode);
msg = convbuf;
}
break;
default: /* A real, normal error code */
for (r = rerrs; r->code >= 0; r++) {
if (r->code == code) {
break;
}
}
if (r->code >= 0) {
msg = r->explain;
} else { /* Unknown; say so */
sprintf(convbuf, unk, code);
msg = convbuf;
}
break;
}
len = strlen(msg) + 1; /* Space needed, including NUL */
if (errbuf_size > 0) {
if (errbuf_size > len) {
strncpy(errbuf, msg, len);
errbuf[len] = '\0';
} else { /* Truncate to fit */
strncpy(errbuf, msg, errbuf_size-1);
errbuf[errbuf_size-1] = '\0';
}
}
return len;
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

View File

@ -1,19 +0,0 @@
{ OB_REG_OKAY, "OB_REG_OKAY", "no errors detected" },
{ OB_REG_NOMATCH, "OB_REG_NOMATCH", "failed to match" },
{ OB_REG_BADPAT, "OB_REG_BADPAT", "invalid regexp (reg version 0.8)" },
{ OB_REG_ECOLLATE, "OB_REG_ECOLLATE", "invalid collating element" },
{ OB_REG_ECTYPE, "OB_REG_ECTYPE", "invalid character class" },
{ OB_REG_EESCAPE, "OB_REG_EESCAPE", "invalid escape \\ sequence" },
{ OB_REG_ESUBREG, "OB_REG_ESUBREG", "invalid backreference number" },
{ OB_REG_EBRACK, "OB_REG_EBRACK", "brackets [] not balanced" },
{ OB_REG_EPAREN, "OB_REG_EPAREN", "parentheses () not balanced" },
{ OB_REG_EBRACE, "OB_REG_EBRACE", "braces {} not balanced" },
{ OB_REG_BADBR, "OB_REG_BADBR", "invalid repetition count(s)" },
{ OB_REG_ERANGE, "OB_REG_ERANGE", "invalid character range" },
{ OB_REG_ESPACE, "OB_REG_ESPACE", "out of memory" },
{ OB_REG_BADRPT, "OB_REG_BADRPT", "quantifier operand invalid" },
{ OB_REG_ASSERT, "OB_REG_ASSERT", "\"can't happen\" -- you found a bug" },
{ OB_REG_INVARG, "OB_REG_INVARG", "invalid argument to regex function" },
{ OB_REG_MIXED, "OB_REG_MIXED", "character widths of regex and string differ" },
{ OB_REG_BADOPT, "OB_REG_BADOPT", "invalid embedded option" },
{ OB_REG_ETOOBIG, "OB_REG_ETOOBIG", "nfa has too many states" },

File diff suppressed because it is too large Load Diff

View File

@ -1,60 +0,0 @@
/*
* ob_regfree - free an RE
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* You might think that this could be incorporated into regcomp.c, and that
* would be a reasonable idea... except that this is a generic function (with
* a generic name), applicable to all compiled REs regardless of the size of
* their characters, whereas the stuff in regcomp.c gets compiled once per
* character size.
*/
#include "regguts.h"
/*
- ob_regfree - free an RE (generic function, punts to RE-specific function)
*
* Ignoring invocation with NULL is a convenience.
*/
void
ob_regfree(
ob_regex_t *re)
{
if (re == NULL) {
return;
}
(*((struct fns *)re->re_fns)->free)(re);
}
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

View File

@ -1,428 +0,0 @@
/*
* Internal interface definitions, etc., for the reg package
*
* Copyright (c) 1998, 1999 Henry Spencer. All rights reserved.
*
* Development of this software was funded, in part, by Cray Research Inc.,
* UUNET Communications Services Inc., Sun Microsystems Inc., and Scriptics
* Corporation, none of whom are responsible for the results. The author
* thanks all of them.
*
* Redistribution and use in source and binary forms -- with or without
* modification -- are permitted for any purpose, provided that
* redistributions in source form retain this entire copyright notice and
* indicate the origin and nature of any modifications.
*
* I'd appreciate being given credit for this package in the documentation of
* software which uses it, but that is not a requirement.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Environmental customization. It should not (I hope) be necessary to alter
* the file you are now reading -- regcustom.h should handle it all, given
* care here and elsewhere.
*/
#include "regcustom.h"
/*
* Things that regcustom.h might override.
*/
/* standard header files (NULL is a reasonable indicator for them) */
#ifndef NULL
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <limits.h>
#include <string.h>
#endif
/* assertions */
#ifndef assert
#ifndef OB_REG_DEBUG
#ifndef NDEBUG
#define NDEBUG /* no assertions */
#endif
#endif /* !OB_REG_DEBUG */
#include <assert.h>
#endif
/* voids */
#ifndef VOID
#define VOID void /* for function return values */
#endif
#ifndef DISCARD
#define DISCARD void /* for throwing values away */
#endif
#ifndef PVOID
#define PVOID void * /* generic pointer */
#endif
#ifndef VS
#define VS(x) ((void*)(x)) /* cast something to generic ptr */
#endif
#ifndef NOPARMS
#define NOPARMS void /* for empty parm lists */
#endif
/* const */
#ifndef CONST1
#define CONST1 const /* for old compilers, might be empty */
#endif
/* function-pointer declarator */
#ifndef FUNCPTR
#if __STDC__ >= 1
#define FUNCPTR(name, args) (*name)args
#else
#define FUNCPTR(name, args) (*name)()
#endif
#endif
/* memory allocation */
#ifndef MALLOC
#define MALLOC(n) malloc(n)
#endif
#ifndef REALLOC
#define REALLOC(p, n) realloc(VS(p), n)
#endif
#ifndef FREE
#define FREE(p) free(VS(p))
#endif
/* want size of a char in bits, and max value in bounded quantifiers */
#ifndef CHAR_BIT
#include <limits.h>
#endif
#ifndef _POSIX2_RE_DUP_MAX
#define _POSIX2_RE_DUP_MAX 255 /* normally from <limits.h> */
#endif
/*
* misc
*/
#define NOTREACHED 0
#define xxx 1
#define DUPMAX _POSIX2_RE_DUP_MAX
#define INFINITY_1 (DUPMAX+1)
#define REMAGIC 0xfed7 /* magic number for main struct */
/*
* debugging facilities
*/
#ifdef OB_REG_DEBUG
/* FDEBUG does finite-state tracing */
#define FDEBUG(arglist) { if (v->eflags&OB_REG_FTRACE) printf arglist; }
/* MDEBUG does higher-level tracing */
#define MDEBUG(arglist) { if (v->eflags&OB_REG_MTRACE) printf arglist; }
#else
#define FDEBUG(arglist) {}
#define MDEBUG(arglist) {}
#endif
/*
* bitmap manipulation
*/
#define UBITS (CHAR_BIT * sizeof(unsigned))
#define BSET(uv, sn) ((uv)[(sn)/UBITS] |= (unsigned)1 << ((sn)%UBITS))
#define ISBSET(uv, sn) ((uv)[(sn)/UBITS] & ((unsigned)1 << ((sn)%UBITS)))
/*
* We dissect a chr into byts for colormap table indexing. Here we define a
* byt, which will be the same as a byte on most machines... The exact size of
* a byt is not critical, but about 8 bits is good, and extraction of 8-bit
* chunks is sometimes especially fast.
*/
#ifndef BYTBITS
#define BYTBITS 8 /* bits in a byt */
#endif
#define BYTTAB (1<<BYTBITS) /* size of table with one entry per byt value */
#define BYTMASK (BYTTAB-1) /* bit mask for byt */
#define NBYTS ((CHRBITS+BYTBITS-1)/BYTBITS)
/* the definition of GETCOLOR(), below, assumes NBYTS <= 4 */
/*
* As soon as possible, we map chrs into equivalence classes -- "colors" --
* which are of much more manageable number.
*/
typedef short color; /* colors of characters */
typedef int pcolor; /* what color promotes to */
#define COLORLESS (-1) /* impossible color */
#define WHITE 0 /* default color, parent of all others */
/*
* A colormap is a tree -- more precisely, a DAG -- indexed at each level by a
* byt of the chr, to map the chr to a color efficiently. Because lower
* sections of the tree can be shared, it can exploit the usual sparseness of
* such a mapping table. The tree is always NBYTS levels deep (in the past it
* was shallower during construction but was "filled" to full depth at the end
* of that); areas that are unaltered as yet point to "fill blocks" which are
* entirely WHITE in color.
*/
/* the tree itself */
struct colors {
color ccolor[BYTTAB];
};
struct ptrs {
union tree *pptr[BYTTAB];
};
union tree {
struct colors colors;
struct ptrs ptrs;
};
#define tcolor colors.ccolor
#define tptr ptrs.pptr
/* Internal per-color descriptor structure for the color machinery */
struct colordesc {
uchr nchrs; /* number of chars of this color */
color sub; /* open subcolor (if any); free chain ptr */
#define NOSUB COLORLESS
struct arc *arcs; /* color chain */
int flags;
#define FREECOL 01 /* currently free */
#define PSEUDO 02 /* pseudocolor, no real chars */
#define UNUSEDCOLOR(cd) ((cd)->flags&FREECOL)
union tree *block; /* block of solid color, if any */
};
/* the color map itself */
struct colormap {
int magic;
#define CMMAGIC 0x876
struct vars *v; /* for compile error reporting */
size_t ncds; /* number of colordescs */
size_t max; /* highest in use */
color free; /* beginning of free chain (if non-0) */
struct colordesc *cd;
#define CDEND(cm) (&(cm)->cd[(cm)->max + 1])
#define NINLINECDS ((size_t)10)
struct colordesc cdspace[NINLINECDS];
union tree tree[NBYTS]; /* tree top, plus fill blocks */
};
/* optimization magic to do fast chr->color mapping */
#define B0(c) ((c) & BYTMASK)
#define B1(c) (((c)>>BYTBITS) & BYTMASK)
#define B2(c) (((c)>>(2*BYTBITS)) & BYTMASK)
#define B3(c) (((c)>>(3*BYTBITS)) & BYTMASK)
#if NBYTS == 1
#define GETCOLOR(cm, c) ((cm)->tree->tcolor[B0(c)])
#endif
/* beware, for NBYTS>1, GETCOLOR() is unsafe -- 2nd arg used repeatedly */
#if NBYTS == 2
#define GETCOLOR(cm, c) ((cm)->tree->tptr[B1(c)]->tcolor[B0(c)])
#endif
#if NBYTS == 4
#define GETCOLOR(cm, c) ((cm)->tree->tptr[B3(c)]->tptr[B2(c)]->tptr[B1(c)]->tcolor[B0(c)])
#endif
/*
* Interface definitions for locale-interface functions in locale.c.
*/
/* Representation of a set of characters. */
struct cvec {
int nchrs; /* number of chrs */
int chrspace; /* number of chrs possible */
chr *chrs; /* pointer to vector of chrs */
int nranges; /* number of ranges (chr pairs) */
int rangespace; /* number of chrs possible */
chr *ranges; /* pointer to vector of chr pairs */
};
/*
* definitions for non-deterministic finite autmaton (NFA) internal
* representation
*
* Having a "from" pointer within each arc may seem redundant, but it saves a
* lot of hassle.
*/
struct state;
struct arc {
int type;
#define ARCFREE '\0'
color co;
struct state *from; /* where it's from (and contained within) */
struct state *to; /* where it's to */
struct arc *outchain; /* *from's outs chain or free chain */
#define freechain outchain
struct arc *inchain; /* *to's ins chain */
struct arc *colorchain; /* color's arc chain */
struct arc *colorchainRev; /* back-link in color's arc chain */
};
struct arcbatch { /* for bulk allocation of arcs */
struct arcbatch *next;
#define ABSIZE 10
struct arc a[ABSIZE];
};
struct state {
int no;
#define FREESTATE (-1)
char flag; /* marks special states */
int nins; /* number of inarcs */
struct arc *ins; /* chain of inarcs */
int nouts; /* number of outarcs */
struct arc *outs; /* chain of outarcs */
struct arc *free; /* chain of free arcs */
struct state *tmp; /* temporary for traversal algorithms */
struct state *next; /* chain for traversing all */
struct state *prev; /* back chain */
struct arcbatch oas; /* first arcbatch, avoid malloc in easy case */
int noas; /* number of arcs used in first arcbatch */
};
struct nfa {
struct state *pre; /* pre-initial state */
struct state *init; /* initial state */
struct state *final; /* final state */
struct state *post; /* post-final state */
int nstates; /* for numbering states */
struct state *states; /* state-chain header */
struct state *slast; /* tail of the chain */
struct state *free; /* free list */
struct colormap *cm; /* the color map */
color bos[2]; /* colors, if any, assigned to BOS and BOL */
color eos[2]; /* colors, if any, assigned to EOS and EOL */
size_t size; /* Current NFA size; differs from nstates as
* it also counts the number of states created
* by children of this state. */
struct vars *v; /* simplifies compile error reporting */
struct nfa *parent; /* parent NFA, if any */
};
/*
* definitions for compacted NFA
*/
struct carc {
color co; /* COLORLESS is list terminator */
int to; /* state number */
};
struct cnfa {
int nstates; /* number of states */
int ncolors; /* number of colors */
int flags;
#define HASLACONS 01 /* uses lookahead constraints */
int pre; /* setup state number */
int post; /* teardown state number */
color bos[2]; /* colors, if any, assigned to BOS and BOL */
color eos[2]; /* colors, if any, assigned to EOS and EOL */
struct carc **states; /* vector of pointers to outarc lists */
struct carc *arcs; /* the area for the lists */
};
#define ZAPCNFA(cnfa) ((cnfa).nstates = 0)
#define NULLCNFA(cnfa) ((cnfa).nstates == 0)
/*
* Used to limit the maximum NFA size to something sane. [Bug 1810264]
*/
#ifndef OB_REG_MAX_STATES
# define OB_REG_MAX_STATES 100000
#endif
/*
* subexpression tree
*/
struct subre {
char op; /* '|', '.' (concat), 'b' (backref), '(',
* '=' */
char flags;
#define LONGER 01 /* prefers longer match */
#define SHORTER 02 /* prefers shorter match */
#define MIXED 04 /* mixed preference below */
#define CAP 010 /* capturing parens below */
#define BACKR 020 /* back reference below */
#define INUSE 0100 /* in use in final tree */
#define LOCAL 03 /* bits which may not propagate up */
#define LMIX(f) ((f)<<2) /* LONGER -> MIXED */
#define SMIX(f) ((f)<<1) /* SHORTER -> MIXED */
#define UP(f) (((f)&~LOCAL) | (LMIX(f) & SMIX(f) & MIXED))
#define MESSY(f) ((f)&(MIXED|CAP|BACKR))
#define PREF(f) ((f)&LOCAL)
#define PREF2(f1, f2) ((PREF(f1) != 0) ? PREF(f1) : PREF(f2))
#define COMBINE(f1, f2) (UP((f1)|(f2)) | PREF2(f1, f2))
short retry; /* index into retry memory */
int subno; /* subexpression number (for 'b' and '(') */
short min; /* min repetitions, for backref only */
short max; /* max repetitions, for backref only */
struct subre *left; /* left child, if any (also freelist chain) */
struct subre *right; /* right child, if any */
struct state *begin; /* outarcs from here... */
struct state *end; /* ...ending in inarcs here */
struct cnfa cnfa; /* compacted NFA, if any */
struct subre *chain; /* for bookkeeping and error cleanup */
};
/*
* table of function pointers for generic manipulation functions. A ob_regex_t's
* re_fns points to one of these.
*/
struct fns {
VOID FUNCPTR(free, (ob_regex_t *));
};
/*
* the insides of a ob_regex_t, hidden behind a void *
*/
struct guts {
int magic;
#define GUTSMAGIC 0xfed9
int cflags; /* copy of compile flags */
long info; /* copy of re_info */
size_t nsub; /* copy of re_nsub */
struct subre *tree;
struct cnfa search; /* for fast preliminary search */
int ntree;
struct colormap cmap;
int FUNCPTR(compare, (CONST1 chr *, CONST1 chr *, size_t));
struct subre *lacons; /* lookahead-constraint vector */
int nlacons; /* size of lacons */
};
/*
* Magic for allocating a variable workspace. This default version is
* stack-hungry.
*/
#ifndef AllocVars
#define AllocVars(vPtr) \
struct vars var; \
register struct vars *vPtr = &var
#endif
#ifndef FreeVars
#define FreeVars(vPtr) ((void) 0)
#endif
/*
* Local Variables:
* mode: c
* c-basic-offset: 4
* fill-column: 78
* End:
*/

View File

@ -334,7 +334,9 @@ inline int ObURowIDData::get_pk_value(ObObjType obj_type, int64_t &pos, ObObj &p
{
int ret = OB_SUCCESS;
const uint8_t version = get_version();
if (OB_UNLIKELY(PK_ROWID_VERSION != version && NO_PK_ROWID_VERSION != version)) {
if (OB_UNLIKELY(PK_ROWID_VERSION != version
&& NO_PK_ROWID_VERSION != version
&& LOB_NO_PK_ROWID_VERSION != version)) {
ret = OB_INVALID_ROWID;
COMMON_LOG(WARN, "invalid rowid version", K(ret), K(version));
} else if (OB_UNLIKELY(obj_type >= ObMaxType)
@ -489,7 +491,9 @@ bool ObURowIDData::is_valid_urowid() const
is_valid = rowid_len_ == HEAP_ORGANIZED_TABLE_ROWID_CONTENT_BUF_SIZE;
} else if (EXT_HEAP_TABLE_ROWID_VERSION == version) {
is_valid = rowid_len_ == EXT_HEAP_ORGANIZED_TABLE_ROWID_CONTENT_BUF_SIZE;
} else if (NO_PK_ROWID_VERSION == version || PK_ROWID_VERSION == version) {
} else if (NO_PK_ROWID_VERSION == version
|| PK_ROWID_VERSION == version
|| LOB_NO_PK_ROWID_VERSION == version) {
int64_t pos = get_pk_content_offset();
ObObj obj;
for (; is_valid && pos < rowid_len_; ) {
@ -516,7 +520,8 @@ bool ObURowIDData::is_valid_version(int64_t v)
} else if (PK_ROWID_VERSION != v
&& NO_PK_ROWID_VERSION != v
&& HEAP_TABLE_ROWID_VERSION != v
&& EXT_HEAP_TABLE_ROWID_VERSION != v) {
&& EXT_HEAP_TABLE_ROWID_VERSION != v
&& LOB_NO_PK_ROWID_VERSION != v) {
if (!is_valid_part_gen_col_version(v)) {
bret = false;
}
@ -542,7 +547,9 @@ uint8_t ObURowIDData::get_version() const
int64_t offset = get_pk_version_offset();
if (offset < rowid_len_) {
raw_version = rowid_content_[offset];
if (PK_ROWID_VERSION == raw_version || NO_PK_ROWID_VERSION == raw_version) {
if (PK_ROWID_VERSION == raw_version
|| NO_PK_ROWID_VERSION == raw_version
|| LOB_NO_PK_ROWID_VERSION == raw_version) {
version = raw_version;
} else if (is_valid_part_gen_col_version(raw_version)) {
version = PK_ROWID_VERSION;

View File

@ -46,6 +46,8 @@ public:
INVALID_ROWID_VERSION = 0,
PK_ROWID_VERSION = 1,
NO_PK_ROWID_VERSION = 2,
LOB_NO_PK_ROWID_VERSION = 3,
HEAP_TABLE_ROWID_VERSION = 128, // 0x80
EXT_HEAP_TABLE_ROWID_VERSION = 160, // 0xA0
};

View File

@ -305,6 +305,7 @@ LATCH_DEF(REWRITE_RULE_ITEM_LOCK, 292, "rewrite rule item lock", LATCH_FIFO, 200
LATCH_DEF(SRS_LOCK, 292, "srs lock", LATCH_READ_PREFER, 2000, 0, SRS_LOCK_WAIT, "srs lock")
LATCH_DEF(DDL_EXECUTE_LOCK, 293, "ddl execute lock", LATCH_FIFO, 2000, 0, DDL_EXECUTE_LOCK_WAIT, "ddl execute lock")
LATCH_DEF(TENANT_IO_CONFIG_LOCK, 294, "tenant io config lock", LATCH_FIFO, 2000, 0, TENANT_IO_CONFIG_WAIT, "tenant io config lock")
LATCH_DEF(SQL_WF_PARTICIPATOR_COND_LOCK, 295, "window function participator lock", LATCH_FIFO, 2000, 0, SQL_WF_PARTICIPATOR_COND_WAIT, "window function participator lock")
LATCH_DEF(LATCH_END, 99999, "latch end", LATCH_FIFO, 2000, 0, WAIT_EVENT_END, "latch end")
#endif

View File

@ -393,7 +393,7 @@ int ObTimeConverter::str_to_datetime(const ObString &str, const ObTimeConvertCtx
if (cvrt_ctx.is_timestamp_) {
local_date_sql_mode.allow_invalid_dates_ = false;
}
if (OB_FAIL(str_to_ob_time_with_date(str, ob_time, scale, false, local_date_sql_mode))) {
if (OB_FAIL(str_to_ob_time_with_date(str, ob_time, scale, false, local_date_sql_mode, cvrt_ctx.need_truncate_))) {
LOG_WARN("failed to convert string to datetime", K(ret));
} else if (!cvrt_ctx.is_timestamp_ && ob_time.is_tz_name_valid_) {
//only enable time zone data type can has tz name and tz addr
@ -792,11 +792,12 @@ int ObTimeConverter::str_to_date(const ObString &str, int32_t &value,
return ret;
}
int ObTimeConverter::str_to_time(const ObString &str, int64_t &value, int16_t *scale, const ObScale &time_scale)
int ObTimeConverter::str_to_time(const ObString &str, int64_t &value, int16_t *scale,
const ObScale &time_scale, const bool &need_truncate)
{
int ret = OB_SUCCESS;
ObTime ob_time(DT_TYPE_TIME);
if (OB_FAIL(str_to_ob_time_without_date(str, ob_time, scale))) {
if (OB_FAIL(str_to_ob_time_without_date(str, ob_time, scale, need_truncate))) {
LOG_WARN("failed to convert string to time", K(ret), K(str));
if (OB_ERR_TRUNCATED_WRONG_VALUE == ret) {
value = ob_time_to_time(ob_time);
@ -1819,7 +1820,7 @@ int ObTimeConverter::get_time_zone(const ObTimeDelims *delims, ObTime &ob_time,
return ret;
}
int ObTimeConverter::str_to_digit_with_date(const ObString &str, ObTimeDigits *digits, ObTime &ob_time)
int ObTimeConverter::str_to_digit_with_date(const ObString &str, ObTimeDigits *digits, ObTime &ob_time, const bool &need_truncate)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(str.ptr()) || OB_UNLIKELY(str.length() <= 0) || OB_ISNULL(digits)) {
@ -1909,7 +1910,7 @@ int ObTimeConverter::str_to_digit_with_date(const ObString &str, ObTimeDigits *d
//if HAS_TYPE_ORACLE, digits[DT_USEC] store nanosecond in fact
const int64_t max_precision = (HAS_TYPE_ORACLE(ob_time.mode_) ? OB_MAX_TIMESTAMP_TZ_PRECISION: OB_MAX_DATETIME_PRECISION);
const bool use_strict_check = HAS_TYPE_ORACLE(ob_time.mode_);
if (OB_FAIL(apply_usecond_delim_rule(delims[DT_SEC], digits[DT_USEC], max_precision, use_strict_check))) {
if (OB_FAIL(apply_usecond_delim_rule(delims[DT_SEC], digits[DT_USEC], max_precision, use_strict_check, need_truncate))) {
LOG_WARN("failed to apply rule", K(use_strict_check), K(ret));
} else if (!(DT_TYPE_DATE & ob_time.mode_) && (DT_TYPE_TIME & ob_time.mode_)) {
if (OB_FAIL(apply_datetime_for_time_rule(ob_time, digits, delims))) {
@ -1931,7 +1932,8 @@ int ObTimeConverter::str_to_digit_with_date(const ObString &str, ObTimeDigits *d
//dayofmonth函数需要容忍月、日为0的错误
int ObTimeConverter::str_to_ob_time_with_date(
const ObString &str, ObTime &ob_time, int16_t *scale,
const bool is_dayofmonth, const ObDateSqlMode date_sql_mode)
const bool is_dayofmonth, const ObDateSqlMode date_sql_mode,
const bool &need_truncate)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(str.ptr()) || OB_UNLIKELY(str.length() <= 0)) {
@ -1939,7 +1941,7 @@ int ObTimeConverter::str_to_ob_time_with_date(
LOG_WARN("datetime string is invalid", K(ret), K(str));
} else {
ObTimeDigits digits[DATETIME_PART_CNT];
if (OB_FAIL(str_to_digit_with_date(str, digits, ob_time))) {
if (OB_FAIL(str_to_digit_with_date(str, digits, ob_time, need_truncate))) {
LOG_WARN("failed to get digits", K(ret), K(str));
} else if (OB_FAIL(validate_datetime(ob_time, is_dayofmonth, date_sql_mode))) {
// OK, it seems like a valid format, now we need check its value.
@ -1983,7 +1985,7 @@ int ObTimeConverter::str_is_date_format(const ObString &str, bool &date_flag)
return ret;
}
int ObTimeConverter::str_to_ob_time_without_date(const ObString &str, ObTime &ob_time, int16_t *scale)
int ObTimeConverter::str_to_ob_time_without_date(const ObString &str, ObTime &ob_time, int16_t *scale, const bool &need_truncate)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(str.ptr()) || OB_UNLIKELY(str.length() <= 0)) {
@ -2090,7 +2092,7 @@ int ObTimeConverter::str_to_ob_time_without_date(const ObString &str, ObTime &ob
// 7 is used for rounding to 6 digits.
if (OB_FAIL(get_datetime_digits(pos, end, 7, digits))) {
LOG_WARN("failed to get digits from datetime string", K(ret));
} else if (OB_FAIL(normalize_usecond_round(digits, OB_MAX_DATETIME_PRECISION))) {
} else if (OB_FAIL(normalize_usecond(digits, OB_MAX_DATETIME_PRECISION, false, need_truncate))) {
LOG_WARN("failed to round usecond", K(ret));
} else {
ob_time.parts_[DT_USEC] = digits.value_; // usecond.
@ -5583,8 +5585,8 @@ OB_INLINE bool ObTimeConverter::is_negative(const char *&str, const char *end)
return ret;
}
OB_INLINE int ObTimeConverter::normalize_usecond_round(ObTimeDigits &digits, const int64_t max_precision,
const bool use_strict_check/*false*/)
OB_INLINE int ObTimeConverter::normalize_usecond(ObTimeDigits &digits, const int64_t max_precision,
const bool use_strict_check/*false*/, const bool &need_truncate)
{
int ret = OB_SUCCESS;
if (OB_UNLIKELY(digits.value_ < 0)
@ -5605,7 +5607,7 @@ OB_INLINE int ObTimeConverter::normalize_usecond_round(ObTimeDigits &digits, con
} else {
// .1234567 will round to 123457.
digits.value_ /= static_cast<int32_t>(power_of_10[digits.len_ - max_precision]);
if (digits.ptr_[max_precision] >= '5') {
if (!need_truncate && digits.ptr_[max_precision] >= '5') {
++digits.value_;
}
}
@ -5668,11 +5670,11 @@ OB_INLINE void ObTimeConverter::apply_date_year2_rule(int64_t &year)
}
OB_INLINE int ObTimeConverter::apply_usecond_delim_rule(ObTimeDelims &second, ObTimeDigits &usecond,
const int64_t max_precision, const bool use_strict_check)
const int64_t max_precision, const bool use_strict_check, const bool &need_truncate)
{
int ret = OB_SUCCESS;
if (is_single_dot(second) && usecond.value_ > 0) {
ret = normalize_usecond_round(usecond, max_precision, use_strict_check);
ret = normalize_usecond(usecond, max_precision, use_strict_check, need_truncate);
} else {
usecond.value_ = 0;
}

View File

@ -293,10 +293,11 @@ struct ObTimeConstStr {
struct ObTimeConvertCtx
{
ObTimeConvertCtx(const ObTimeZoneInfo *tz_info, const bool is_timestamp)
ObTimeConvertCtx(const ObTimeZoneInfo *tz_info, const bool is_timestamp, const bool &need_truncate = false)
:tz_info_(tz_info),
oracle_nls_format_(),
is_timestamp_(is_timestamp) {}
is_timestamp_(is_timestamp),
need_truncate_(need_truncate) {}
ObTimeConvertCtx(const ObTimeZoneInfo *tz_info, const ObString &oracle_nls_format, const bool is_timestamp)
:tz_info_(tz_info),
oracle_nls_format_(oracle_nls_format),
@ -304,6 +305,7 @@ struct ObTimeConvertCtx
const ObTimeZoneInfo *tz_info_;
ObString oracle_nls_format_;
bool is_timestamp_; //means mysql timestamp?
bool need_truncate_;
};
class ObTimeConverter
{
@ -406,7 +408,8 @@ public:
static int str_is_date_format(const ObString &str, bool &date_flag);
static int str_to_date(const ObString &str, int32_t &value, const ObDateSqlMode date_sql_mode = 0);
static int str_to_time(const ObString &str, int64_t &value, int16_t *scale = NULL, const ObScale &time_scale = 0);
static int str_to_time(const ObString &str, int64_t &value, int16_t *scale = NULL,
const ObScale &time_scale = 0, const bool &need_truncate = false);
static int str_to_year(const ObString &str, uint8_t &value);
static int str_to_interval(const ObString &str, ObDateUnitType unit_type, int64_t &value);
// int / double / string <- datetime(timestamp) / date / time / year.
@ -478,8 +481,8 @@ public:
const ObDateSqlMode date_sql_mode);
static int int_to_ob_time_without_date(int64_t time_second, ObTime &ob_time, int64_t nano_second = 0);
static int str_to_ob_time_with_date(const ObString &str, ObTime &ob_time, int16_t *scale,
const bool is_dayofmonth, const ObDateSqlMode date_sql_mode);
static int str_to_ob_time_without_date(const ObString &str, ObTime &ob_time, int16_t *scale = NULL);
const bool is_dayofmonth, const ObDateSqlMode date_sql_mode, const bool &need_truncate = false);
static int str_to_ob_time_without_date(const ObString &str, ObTime &ob_time, int16_t *scale = NULL, const bool &need_truncate = false);
static int str_to_ob_time_format(const ObString &str, const ObString &fmt, ObTime &ob_time,
int16_t *scale, const bool no_zero_in_date,
const ObDateSqlMode date_sql_mode);
@ -647,7 +650,7 @@ private:
static int get_datetime_delims(const char *&str, const char *end, ObTimeDelims &delims);
static int get_datetime_digits_delims(const char *&str, const char *end,
int32_t max_len, ObTimeDigits &digits, ObTimeDelims &delims);
static int str_to_digit_with_date(const ObString &str, ObTimeDigits *digits, ObTime &obtime);
static int str_to_digit_with_date(const ObString &str, ObTimeDigits *digits, ObTime &obtime, const bool &need_truncate = false);
static int get_time_zone(const ObTimeDelims *delims, ObTime &ob_time, const char *end_ptr);
static void skip_delims(const char *&str, const char *end);
static bool is_year4(int64_t first_token_len);
@ -657,14 +660,14 @@ private:
static bool is_all_spaces(const ObTimeDelims &delims);
static bool has_any_space(const ObTimeDelims &delims);
static bool is_negative(const char *&str, const char *end);
static int normalize_usecond_round(ObTimeDigits &digits, const int64_t max_precision,
const bool use_strict_check = false);
static int normalize_usecond(ObTimeDigits &digits, const int64_t max_precision,
const bool use_strict_check = false, const bool &need_truncate = false);
static int normalize_usecond_trunc(ObTimeDigits &digits, bool need_trunc);
static int apply_date_space_rule(const ObTimeDelims *delims);
static void apply_date_year2_rule(ObTimeDigits &year);
static void apply_date_year2_rule(int32_t &year);
static void apply_date_year2_rule(int64_t &year);
static int apply_usecond_delim_rule(ObTimeDelims &second, ObTimeDigits &usecond, const int64_t max_precision, const bool use_strict_check);
static int apply_usecond_delim_rule(ObTimeDelims &second, ObTimeDigits &usecond, const int64_t max_precision, const bool use_strict_check, const bool &truncate = false);
static int apply_datetime_for_time_rule(ObTime &ob_time, const ObTimeDigits *digits, const ObTimeDelims *delims);
// static int find_time_range(int64_t t, const int64_t *range_boundaries, uint64_t higher_bound, uint64_t& result);
// static int find_transition_type(int64_t t, const ObTimeZoneInfo *sp, TRAN_TYPE_INFO *& result);

View File

@ -28,10 +28,8 @@ ObFLTSpanMgr* __attribute__((weak)) get_flt_span_manager()
{
return nullptr;
}
int __attribute__((weak)) handle_span_record(char* buf, const int64_t buf_len, ObFLTSpanMgr* flt_span_manager)
int __attribute__((weak))handle_span_record(ObFLTSpanMgr *flt_span_manager, char* tag_buf, int64_t tag_len, ::oceanbase::trace::ObSpanCtx* span)
{
UNUSED(buf);
UNUSED(buf_len);
UNUSED(flt_span_manager);
return 0;
}
@ -49,17 +47,6 @@ if (OB_NOT_NULL(span) && 0 == span->span_id_.high_) { \
span->span_id_.low_ = UUID::gen_rand(); \
span->span_id_.high_ = span->start_ts_; \
}
static const char* __span_type_mapper[] = {
#define FLT_DEF_SPAN(name, comment) #name,
#define __HIGH_LEVEL_SPAN
#define __MIDDLE_LEVEL_SPAN
#define __LOW_LEVEL_SPAN
#include "lib/trace/ob_trace_def.h"
#undef __LOW_LEVEL_SPAN
#undef __MIDDLE_LEVEL_SPAN
#undef __HIGH_LEVEL_SPAN
#undef FLT_DEF_SPAN
};
thread_local ObTrace* ObTrace::save_buffer = nullptr;
void flush_trace()
@ -119,7 +106,7 @@ void flush_trace()
span->is_follow_ ? "true" : "false",
buf);
buf[0] = '\0';
IGNORE_RETURN sql::handle_span_record(buf, MAX_TRACE_LOG_SIZE, sql::get_flt_span_manager());
IGNORE_RETURN sql::handle_span_record(sql::get_flt_span_manager(), buf, pos, span);
if (0 != span->end_ts_) {
current_span.remove(span);
trace.freed_span_.add_first(span);
@ -432,6 +419,7 @@ ObSpanCtx* ObTrace::begin_span(uint32_t span_type, uint8_t level, bool is_follow
current_span_.add_first(new_span);
new_span->span_type_ = span_type;
new_span->span_id_.low_ = ++seq_;
new_span->span_id_.high_ = 0;
new_span->source_span_ = last_active_span_;
new_span->is_follow_ = is_follow;
new_span->start_ts_ = ObTimeUtility::fast_current_time();
@ -443,6 +431,18 @@ ObSpanCtx* ObTrace::begin_span(uint32_t span_type, uint8_t level, bool is_follow
return new_span;
}
// used in ddl task tracing
ObSpanCtx* ObTrace::begin_span_by_id(const uint32_t span_type, const uint8_t level,
const bool is_follow, const UUID span_id, const int64_t start_ts)
{
ObSpanCtx *span = begin_span(span_type, level, is_follow);
if (OB_NOT_NULL(span)) {
span->span_id_ = span_id;
span->start_ts_ = start_ts;
}
return span;
}
void ObTrace::end_span(ObSpanCtx* span)
{
if (!trace_id_.is_inited() || OB_ISNULL(span) || !span->span_id_.is_inited()) {
@ -453,6 +453,19 @@ void ObTrace::end_span(ObSpanCtx* span)
}
}
// used in ddl task tracing
void ObTrace::release_span(ObSpanCtx *&span)
{
if (!trace_id_.is_inited() || OB_ISNULL(span) || !span->span_id_.is_inited()) {
// do nothing
} else {
end_span(span);
current_span_.remove(span);
freed_span_.add_first(span);
span = nullptr;
}
}
void ObTrace::reset_span()
{
#ifndef NDEBUG
@ -555,5 +568,10 @@ void ObTrace::dump_span()
_LIB_LOG(WARN, "%s backtrace: %s", buf, lbt());
}
OB_SERIALIZE_MEMBER(FltTransCtx,
trace_id_,
span_id_,
policy_);
}
}

View File

@ -39,15 +39,10 @@ if (OB_NOT_NULL(span)) { \
#define FLT_SET_TRACE_LEVEL(level) (OBTRACE->set_level(level))
#define FLT_SET_AUTO_FLUSH(value) (OBTRACE->set_auto_flush(value))
namespace oceanbase
{
namespace sql
{
class ObFLTSpanMgr;
extern ObFLTSpanMgr* get_flt_span_manager();
extern int handle_span_record(char* buf, const int64_t buf_len, ObFLTSpanMgr* flt_span_manager);
}
}
#define FLT_RESTORE_DDL_TRACE_CTX(flt_ctx) (OBTRACE->init(flt_ctx))
#define FLT_RESTORE_DDL_SPAN(span_type, span_id, start_ts) (OBTRACE->begin_span_by_id(::oceanbase::trace::ObSpanType::span_type, GET_SPANLEVEL(::oceanbase::trace::ObSpanType::span_type), false, span_id, start_ts))
#define FLT_RELEASE_DDL_SPAN(span) (OBTRACE->release_span(span))
#define FLUSH_TRACE() ::oceanbase::trace::flush_trace();
#define FLTSpanGuard(span_type) ::oceanbase::trace::__ObFLTSpanGuard __##span_type##__LINE__(::oceanbase::trace::ObSpanType::span_type, GET_SPANLEVEL(::oceanbase::trace::ObSpanType::span_type))
@ -58,6 +53,18 @@ namespace oceanbase
{
namespace trace
{
static const char* __span_type_mapper[] = {
#define FLT_DEF_SPAN(name, comment) #name,
#define __HIGH_LEVEL_SPAN
#define __MIDDLE_LEVEL_SPAN
#define __LOW_LEVEL_SPAN
#include "lib/trace/ob_trace_def.h"
#undef __LOW_LEVEL_SPAN
#undef __MIDDLE_LEVEL_SPAN
#undef __HIGH_LEVEL_SPAN
#undef FLT_DEF_SPAN
};
extern void flush_trace();
struct UUID
@ -98,6 +105,7 @@ struct UUID
};
struct FltTransCtx {
OB_UNIS_VERSION(1);
public:
FltTransCtx()
: trace_id_(), span_id_(), policy_(0)
@ -225,6 +233,13 @@ struct ObTrace
UUID begin();
void end();
ObSpanCtx* begin_span(uint32_t span_type, uint8_t level, bool is_follow);
// used in ddl task tracing
ObSpanCtx* begin_span_by_id(const uint32_t span_type,
const uint8_t level,
const bool is_follow,
const UUID span_id,
const int64_t start_ts);
void release_span(ObSpanCtx *&span);
void end_span(ObSpanCtx* span_id);
void reset_span();
template <typename T, typename... Targs>
@ -246,6 +261,7 @@ struct ObTrace
OB_INLINE UUID get_trace_id() { return trace_id_; }
OB_INLINE UUID get_root_span_id() { return root_span_id_; }
OB_INLINE uint8_t get_policy() { return policy_; }
OB_INLINE uint8_t get_level() { return level_; }
OB_INLINE void set_level(uint8_t level) { level_ = 0x7f & level; }
OB_INLINE void set_auto_flush(bool auto_flush) { auto_flush_ = auto_flush; }
OB_INLINE bool is_auto_flush() { return auto_flush_; }
@ -348,4 +364,14 @@ int ObTagCtx<char*>::tostring(char* buf, const int64_t buf_len, int64_t& pos);
} // trace
} // oceanbase
namespace oceanbase
{
namespace sql
{
class ObFLTSpanMgr;
extern ObFLTSpanMgr* get_flt_span_manager();
extern int handle_span_record(char* buf, const int64_t buf_len, ObFLTSpanMgr* flt_span_manager, ::oceanbase::trace::ObSpanCtx* span);
}
}
#endif /* _OB_TRACE_H */

View File

@ -40,6 +40,8 @@ FLT_DEF_SPAN(com_query_process, "com_query process")
FLT_DEF_SPAN(close, "close plan")
FLT_DEF_SPAN(cmd_execute, "command execute")
FLT_DEF_SPAN(cmd_open, "command open")
FLT_DEF_SPAN(remote_execute, "remote execute")
FLT_DEF_SPAN(remote_compile, "compile for remote sql")
// **** for sql end ****
// **** for pl ****
@ -84,6 +86,48 @@ FLT_DEF_SPAN(com_query_process, "com_query process")
FLT_DEF_SPAN(fetch_das_extra_result, "fetch das extra result")
FLT_DEF_SPAN(fetch_das_result_process, "fetch das result process")
// for ddl task
FLT_DEF_SPAN(ddl_prepare, "prepare phase of ddl task")
FLT_DEF_SPAN(ddl_failure_cleanup, "cleanup phase of ddl task failure")
FLT_DEF_SPAN(ddl_success, "success check of ddl task")
FLT_DEF_SPAN(ddl_wait_trans_end, "wait for all previous transaction finish")
FLT_DEF_SPAN(ddl_lock_table, "lock table")
FLT_DEF_SPAN(ddl_redefinition, "redefinition phase of ddl task")
FLT_DEF_SPAN(ddl_copy_table_dependent_objects, "copy table dependent object")
FLT_DEF_SPAN(ddl_modify_autoinc, "modify autoincrease column")
FLT_DEF_SPAN(ddl_take_effect, "index take effect")
FLT_DEF_SPAN(ddl_check_table_empty, "check table empty")
// build index task
FLT_DEF_SPAN(ddl_build_index, "ddl build index task")
FLT_DEF_SPAN(ddl_validate_checksum, "ddl task verify checksum")
// drop index task
FLT_DEF_SPAN(ddl_drop_index, "ddl drop index task")
FLT_DEF_SPAN(ddl_set_write_only, "set index to write only mode")
FLT_DEF_SPAN(ddl_set_unusable, "set index to unusable state")
FLT_DEF_SPAN(ddl_drop_schema, "drop index schema")
// drop primary key task
FLT_DEF_SPAN(ddl_drop_primary_key, "ddl drop primary key task")
// table redefinition task
FLT_DEF_SPAN(ddl_table_redefinition, "ddl table redefinition task")
// column redefinition task
FLT_DEF_SPAN(ddl_column_redefinition, "ddl column redefinition task")
// ddl constraint task
FLT_DEF_SPAN(ddl_constraint, "ddl constraint task")
FLT_DEF_SPAN(ddl_check_constraint_valid, "check constraint valid")
FLT_DEF_SPAN(ddl_set_constraint_valid, "set constraint valid")
// ddl modify autoinc
FLT_DEF_SPAN(ddl_modify_autoinc_task, "ddl modify autoincrease column task")
// ddl retry task
FLT_DEF_SPAN(ddl_retry_task, "ddl_ retry task")
#endif // __HIGH_LEVEL_SPAN
#ifdef __MIDDLE_LEVEL_SPAN
@ -157,6 +201,19 @@ FLT_DEF_TAG(index_block_cache_hits, "index block cache hit count")
FLT_DEF_TAG(sstable_read_cnt, "sstable count involved in the scan")
FLT_DEF_TAG(rescan_read_cnt, "table scan iterator rescan count")
// ddl task
FLT_DEF_TAG(ddl_task_id, "ddl task id")
FLT_DEF_TAG(ddl_parent_task_id, "ddl parent task id")
FLT_DEF_TAG(ddl_data_table_id, "data table id")
FLT_DEF_TAG(ddl_index_table_id, "index table id")
FLT_DEF_TAG(ddl_snapshot_version, "snapshot version")
FLT_DEF_TAG(ddl_schema_version, "schema version")
FLT_DEF_TAG(ddl_is_unique_index, "is unique index")
FLT_DEF_TAG(ddl_is_global_index, "is global index")
FLT_DEF_TAG(ddl_need_verify, "need verify")
FLT_DEF_TAG(ddl_check_unique_snapshot, "check unique snapshot")
FLT_DEF_TAG(ddl_ret_code, "return value")
// debug
FLT_DEF_TAG(span_back_trace, "full link tracing debug")
#endif // __HIGH_LEVEL_TAG

View File

@ -501,7 +501,7 @@ class EventTable
EN_OPEN_REMOTE_ASYNC_EXECUTION = 244,
EN_BACKUP_DELETE_EXCEPTION_HANDLING = 245,
EN_SORT_IMPL_FORCE_DO_DUMP = 246,
EN_ENFORCE_PUSH_DOWN_WF = 247,
//
EN_TRANS_SHARED_LOCK_CONFLICT = 250,
EN_HASH_JOIN_OPTION = 251,

View File

@ -295,7 +295,8 @@ WAIT_EVENT_DEF(DEADLOCK_DETECT_LOCK_WAIT, 15247, "spinlock: deadlock detect lock
WAIT_EVENT_DEF(SRS_LOCK_WAIT, 15251, "latch: srs lock wait", "address", "number", "tries", CONCURRENCY, "latch: srs lock wait", true)
WAIT_EVENT_DEF(CLOG_CKPT_RWLOCK_WAIT, 15252, "rwlock: clog checkpoint rwlock wait", "address", "number", "tries", CONCURRENCY, "rwlock: clog checkpoint rwlock wait", true)
WAIT_EVENT_DEF(TENANT_IO_CONFIG_WAIT, 15253, "rwlock: tenant io config wait", "address", "number", "tries", CONCURRENCY, "rwlock: tenant io config wait", true)
WAIT_EVENT_DEF(SQL_WF_PARTICIPATOR_LOCK_WAIT, 15254, "latch: window function participator cond lock wait", "address", "", "", CONCURRENCY, "window function participator cond lock wait", true)
WAIT_EVENT_DEF(SQL_WF_PARTICIPATOR_COND_WAIT, 15255, "mutex: window function participator cond wait", "address", "", "", CONCURRENCY, "window function participator cond wait", true)
//transaction
WAIT_EVENT_DEF(END_TRANS_WAIT, 16001, "wait end trans", "rollback", "trans_hash_value", "participant_count", COMMIT,"wait end trans", false)

View File

@ -38,6 +38,7 @@ ob_set_subtarget(oblib_rpc obmysql
obmysql/ob_sql_sock_session.cpp
obmysql/ob_virtual_cs_protocol_processor.cpp
obmysql/obp20_extra_info.cpp
obmysql/ob_packet_record.cpp
)
ob_set_subtarget(oblib_rpc obmysql_packet

View File

@ -346,13 +346,17 @@ int Ob20ProtocolProcessor::decode_new_extra_info(const Ob20ProtocolHeader &hdr,
int Ob20ProtocolProcessor::do_splice(ObSMConnection& conn, ObICSMemPool& pool, void*& pkt, bool& need_decode_more)
{
INIT_SUCC(ret);
if (OB_FAIL(process_ob20_packet(conn.proto20_pkt_context_, conn.mysql_pkt_context_, pool, pkt, need_decode_more))) {
if (OB_FAIL(process_ob20_packet(conn.proto20_pkt_context_, conn.mysql_pkt_context_,
conn.pkt_rec_wrapper_, pool, pkt, need_decode_more))) {
LOG_ERROR("fail to process_ob20_packet", K(ret));
}
return ret;
}
inline int Ob20ProtocolProcessor::process_ob20_packet(ObProto20PktContext& context, ObMysqlPktContext &mysql_pkt_context, ObICSMemPool& pool,
inline int Ob20ProtocolProcessor::process_ob20_packet(ObProto20PktContext& context,
ObMysqlPktContext &mysql_pkt_context,
obmysql::ObPacketRecordWrapper &pkt_rec_wrapper,
ObICSMemPool& pool,
void *&ipacket, bool &need_decode_more)
{
INIT_SUCC(ret);
@ -382,6 +386,9 @@ inline int Ob20ProtocolProcessor::process_ob20_packet(ObProto20PktContext& conte
if (OB_SUCC(ret)) {
uint32_t mysql_data_size = pkt20->get_mysql_packet_len();
char *mysql_data_start = const_cast<char *>(pkt20->get_cdata());
if (pkt_rec_wrapper.enable_proto_dia()) {
pkt_rec_wrapper.record_recieve_mysql_pkt_fragment(mysql_data_size);
}
if (mysql_data_size == 0) {
// waitting for a not empty packet
need_decode_more = true;
@ -413,6 +420,9 @@ inline int Ob20ProtocolProcessor::process_ob20_packet(ObProto20PktContext& conte
// set again for sending response
context.proto20_last_pkt_seq_ = pkt20->get_seq();
context.proto20_last_request_id_ = pkt20->get_request_id();
if (pkt_rec_wrapper.enable_proto_dia()) {
pkt_rec_wrapper.record_recieve_obp20_packet(*pkt20, *input_packet);
}
}
}
}

View File

@ -15,6 +15,7 @@
#include "rpc/obmysql/ob_mysql_protocol_processor.h"
#include "rpc/obmysql/obp20_extra_info.h"
#include "rpc/obmysql/ob_packet_record.h"
namespace oceanbase
{
@ -47,7 +48,8 @@ private:
const char*& payload_start,
Ob20ExtraInfo &extra_info);
int decode_ob20_body(ObICSMemPool& pool, const char*& buf, const Ob20ProtocolHeader &hdr, rpc::ObPacket *&pkt);
int process_ob20_packet(ObProto20PktContext& context, ObMysqlPktContext &mysql_pkt_context, ObICSMemPool& pool,
int process_ob20_packet(ObProto20PktContext& context, ObMysqlPktContext &mysql_pkt_context,
obmysql::ObPacketRecordWrapper &pkt_rec_wrapper, ObICSMemPool& pool,
void *&ipacket, bool &need_decode_more);
Obp20Decoder* svr_decoders_[OBP20_SVR_END-OBP20_PROXY_MAX_TYPE] = {
&trace_info_dcd_,

View File

@ -98,7 +98,11 @@ int ObProto20Utils::do_packet_encode(ObProtoEncodeParam &param) {
ObEasyBuffer easy_buffer(*param.ez_buf_);
//SET_OB_LOG_TRACE_MODE(); // prevent printing log
int32_t old_len = param.seri_size_;
ret = param.pkt_->encode(easy_buffer.last(), easy_buffer.write_avail_size(), param.seri_size_);
if (param.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
param.conn_->pkt_rec_wrapper_.record_send_mysql_pkt(*param.pkt_, param.seri_size_ - old_len);
}
//if (((OB_SIZE_OVERFLOW != ret) && (OB_BUF_NOT_ENOUGH != ret) && (common::OB_SUCCESS != ret))
// || ((IS_LOG_ENABLED(INFO) && (OB_LOG_NEED_TO_PRINT(DEBUG))))) {
// PRINT_OB_LOG_TRACE_BUF(INFO);
@ -138,6 +142,9 @@ inline int ObProto20Utils::do_proto20_packet_encode(ObProtoEncodeParam &param)
switch (proto20_context.next_step_) {
case START_TO_FILL_STEP: {
proto20_context.next_step_ = RESERVE_HEADER_STEP;
if (param.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
param.conn_->pkt_rec_wrapper_.begin_seal_obp20_pkt();
}
break;
}
case RESERVE_HEADER_STEP: {
@ -465,6 +472,9 @@ inline int ObProto20Utils::fill_proto20_payload(ObProtoEncodeParam &param, bool
easy_buffer.write(seri_size);
param.is_pkt_encoded_ = true;
// noting break, wait to encode next one
if (param.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
param.conn_->pkt_rec_wrapper_.record_send_mysql_pkt(*param.pkt_, seri_size);
}
need_break = true;
} else if (split_count > 1) {
if (OB_FAIL(param.save_large_packet(easy_buffer.last(), seri_size))) {
@ -477,6 +487,10 @@ inline int ObProto20Utils::fill_proto20_payload(ObProtoEncodeParam &param, bool
if (OB_FAIL(param.add_pos(ObProtoEncodeParam::PROTO20_SPLIT_LEN))) {
LOG_ERROR("fail to add pos", K(ObProtoEncodeParam::PROTO20_SPLIT_LEN), K(ret));
}
if (param.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
param.conn_->pkt_rec_wrapper_.record_send_mysql_pkt(*param.pkt_,
ObProtoEncodeParam::PROTO20_SPLIT_LEN);
}
}
proto20_context.next_step_ = FILL_TAILER_STEP;
}
@ -559,12 +573,9 @@ inline int ObProto20Utils::fill_proto20_header(ObProtoEncodeParam &param) {
uint16_t header_checksum = 0;
int64_t pos = 0;
char *start = easy_buffer.begin();
observer::ObSMConnection *conn = NULL;
if (OB_ISNULL(param.req_)) {
LOG_ERROR("request is null");
} else if (FALSE_IT(conn = reinterpret_cast<observer::ObSMConnection *>(
SQL_REQ_OP.get_sql_session(param.req_)))) {
} else if (FALSE_IT(packet_seq = conn->proto20_pkt_context_.proto20_last_pkt_seq_ + 1)) {
} else if (FALSE_IT(packet_seq = param.conn_->proto20_pkt_context_.proto20_last_pkt_seq_ + 1)) {
} else if (OB_UNLIKELY(compress_len > OB_MYSQL_MAX_PAYLOAD_LENGTH)) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("invalid compress_len", K(compress_len), K(OB_MYSQL_MAX_PAYLOAD_LENGTH), K(ret));
@ -591,8 +602,12 @@ inline int ObProto20Utils::fill_proto20_header(ObProtoEncodeParam &param) {
} else if (OB_FAIL(ObMySQLUtil::store_int2(start, proto20_context.header_len_, reserved, pos))) {
LOG_ERROR("fail to store int2", K(ret));
} else {
++conn->proto20_pkt_context_.proto20_last_pkt_seq_;
++param.conn_->proto20_pkt_context_.proto20_last_pkt_seq_;
// calc header checksum
if (param.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
param.conn_->pkt_rec_wrapper_.end_seal_obp20_pkt((uint32_t)(payload_len), flag, packet_seq, 0,
request_id, compress_len, compress_seq);
}
if (!proto20_context.is_checksum_off_) {
header_checksum = ob_crc16(0, reinterpret_cast<uint8_t *>(start), pos);
}

View File

@ -20,6 +20,7 @@
#include "rpc/obmysql/ob_mysql_packet.h"
#include "rpc/ob_request.h"
#include "rpc/obmysql/obp20_extra_info.h"
#include "rpc/obmysql/obsm_struct.h"
namespace oceanbase
{
@ -118,6 +119,7 @@ public:
int64_t large_pkt_buf_pos_;
common::ObIArray<ObObjKV> *extra_info_kvs_;
common::ObIArray<Obp20Encoder*> *extra_info_ecds_;
observer::ObSMConnection* conn_;
const static int64_t MAX_PROTO20_PAYLOAD_LEN;
const static int64_t PROTO20_SPLIT_LEN;
@ -128,11 +130,11 @@ public:
seri_size_(0), conn_id_(0), encode_ret_(common::OB_SUCCESS),
need_flush_(false), is_last_(false), is_pkt_encoded_(false),
large_pkt_buf_(NULL), large_pkt_buf_len_(0), large_pkt_buf_pos_(0),
extra_info_kvs_(NULL), extra_info_ecds_(NULL)
extra_info_kvs_(NULL), extra_info_ecds_(NULL), conn_(NULL)
{}
inline bool is_valid() const
{ return (NULL != proto20_context_) && (NULL != ez_buf_) && (NULL != req_); }
{ return (NULL != proto20_context_) && (NULL != ez_buf_) && (NULL != req_) && (NULL != conn_); }
inline static void build_param(ObProtoEncodeParam &param, ObMySQLPacket *pkt,
easy_buf_t &ez_buf, const uint32_t sessid, const bool is_last,
@ -148,6 +150,10 @@ public:
param.req_ = req;
param.extra_info_kvs_ = extra_info;
param.extra_info_ecds_ = extra_info_ecds;
if (NULL != param.req_) {
param.conn_ = reinterpret_cast<observer::ObSMConnection *>
(SQL_REQ_OP.get_sql_session(param.req_));
}
}
inline int add_pos(const int64_t delta);

View File

@ -17,6 +17,7 @@
#include "rpc/obmysql/ob_mysql_request_utils.h"
#include "lib/compress/zlib/ob_zlib_compressor.h"
#include "rpc/obmysql/obsm_struct.h"
#include "rpc/obmysql/ob_packet_record.h"
namespace oceanbase
{
@ -77,7 +78,8 @@ int ObMysqlCompressProtocolProcessor::do_decode(ObSMConnection& conn, ObICSMemPo
int ObMysqlCompressProtocolProcessor::do_splice(observer::ObSMConnection& conn, ObICSMemPool& pool, void*& pkt, bool& need_decode_more)
{
INIT_SUCC(ret);
if (OB_FAIL(process_compressed_packet(conn.compressed_pkt_context_, conn.mysql_pkt_context_, pool, pkt, need_decode_more))) {
if (OB_FAIL(process_compressed_packet(conn.compressed_pkt_context_, conn.mysql_pkt_context_,
conn.pkt_rec_wrapper_, pool, pkt, need_decode_more))) {
LOG_ERROR("fail to process_compressed_packet", K(ret));
}
return ret;
@ -143,7 +145,8 @@ inline int ObMysqlCompressProtocolProcessor::decode_compressed_packet(
}
inline int ObMysqlCompressProtocolProcessor::process_compressed_packet(
ObCompressedPktContext& context, ObMysqlPktContext &mysql_pkt_context, ObICSMemPool& pool,
ObCompressedPktContext& context, ObMysqlPktContext &mysql_pkt_context,
obmysql::ObPacketRecordWrapper &pkt_rec_wrapper, ObICSMemPool& pool,
void *&ipacket, bool &need_decode_more)
{
int ret = OB_SUCCESS;
@ -163,7 +166,9 @@ inline int ObMysqlCompressProtocolProcessor::process_compressed_packet(
? iraw_pkt->get_comp_len()
: iraw_pkt->get_uncomp_len());
int64_t alloc_size = static_cast<int64_t>(decompress_data_size);
if (pkt_rec_wrapper.enable_proto_dia()) {
pkt_rec_wrapper.record_recieve_mysql_pkt_fragment(iraw_pkt->get_comp_len());
}
//in order to reuse optimize memory, we put decompressed data into raw_pkt directly
char *tmp_buffer = NULL;
if (OB_ISNULL(tmp_buffer = reinterpret_cast<char *>(pool.alloc(alloc_size)))) {
@ -184,6 +189,15 @@ inline int ObMysqlCompressProtocolProcessor::process_compressed_packet(
if (need_decode_more) {
context.is_multi_pkt_ = true;
} else {
if (pkt_rec_wrapper.enable_proto_dia()) {
ObMySQLRawPacket *raw_pkt = NULL;
if (OB_ISNULL(raw_pkt = reinterpret_cast<ObMySQLRawPacket *>(ipacket))) {
ret = OB_ERR_UNEXPECTED;
LOG_ERROR("ipacket is null", K(ret));
} else {
pkt_rec_wrapper.record_recieve_comp_packet(*iraw_pkt, *raw_pkt);
}
}
context.reset();
}
}

View File

@ -46,7 +46,8 @@ private:
const uint32_t pktlen_before_compress, char *&pkt_body,
const uint32_t pkt_body_size);
int process_compressed_packet(ObCompressedPktContext& context, ObMysqlPktContext &mysql_pkt_context, ObICSMemPool& pool,
int process_compressed_packet(ObCompressedPktContext& context, ObMysqlPktContext &mysql_pkt_context,
obmysql::ObPacketRecordWrapper &pkt_rec_wrapper, ObICSMemPool& pool,
void *&ipacket, bool &need_decode_more);
private:

View File

@ -91,6 +91,23 @@ enum ObMySQLCmd
COM_MAX_NUM
};
enum class ObMySQLPacketType
{
INVALID_PKT = 0,
PKT_MYSQL, // 1 -> mysql packet;
PKT_OKP, // 2 -> okp;
PKT_ERR, // 3 -> error packet;
PKT_EOF, // 4 -> eof packet;
PKT_ROW, // 5 -> row packet;
PKT_FIELD, // 6 -> field packet;
PKT_PIECE, // 7 -> piece packet;
PKT_STR, // 8 -> string packet;
PKT_PREPARE, // 9 -> prepare packet;
PKT_RESHEAD, // 10 -> result header packet
PKT_PREXEC, // 11 -> prepare execute packet;
PKT_END // 12 -> end of packet type
};
union ObServerStatusFlags
{
ObServerStatusFlags() : flags_(0) {}
@ -411,7 +428,9 @@ public:
virtual int64_t get_serialize_size() const;
int encode(char *buffer, int64_t length, int64_t &pos, int64_t &pkt_count) const;
int encode(char *buffer, int64_t length, int64_t &pos);
int get_pkt_len() { return hdr_.len_; }
virtual int decode() { return common::OB_NOT_SUPPORTED; }
virtual ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::INVALID_PKT; }
virtual void reset()
{

View File

@ -18,6 +18,7 @@
#include "rpc/obmysql/packet/ompk_ssl_request.h"
#include "rpc/obmysql/ob_mysql_request_utils.h"
#include "rpc/obmysql/obsm_struct.h"
#include "rpc/obmysql/ob_packet_record.h"
namespace oceanbase
{
@ -113,7 +114,10 @@ int ObMysqlProtocolProcessor::do_decode(ObSMConnection& conn, ObICSMemPool& pool
int ObMysqlProtocolProcessor::do_splice(ObSMConnection& conn, ObICSMemPool& pool, void*& pkt, bool& need_decode_more)
{
INIT_SUCC(ret);
if (OB_FAIL(process_mysql_packet(conn.mysql_pkt_context_, pool, pkt, need_decode_more))) {
__builtin_prefetch(&conn.pkt_rec_wrapper_.pkt_rec_[conn.pkt_rec_wrapper_.cur_pkt_pos_
% ObPacketRecordWrapper::REC_BUF_SIZE]);
if (OB_FAIL(process_mysql_packet(conn.mysql_pkt_context_, &conn.pkt_rec_wrapper_,
pool, pkt, need_decode_more))) {
LOG_ERROR("fail to process_mysql_packet", K(ret));
}
return ret;
@ -276,7 +280,8 @@ int ObMysqlProtocolProcessor::read_body(
context.raw_pkt_.set_content(start + pos, static_cast<uint32_t>(context.payload_len_));
const int64_t actual_data_len = handle_len;
void *tmp_ipacket = reinterpret_cast<void *>(&context.raw_pkt_);
if (OB_FAIL(process_one_mysql_packet(context, pool, actual_data_len, tmp_ipacket, need_decode_more))) {
if (OB_FAIL(process_one_mysql_packet(context, NULL, pool, actual_data_len,
tmp_ipacket, need_decode_more))) {
LOG_ERROR("fail to process one mysql packet", K(context), K(ret));
} else {
if (need_decode_more) { // mysql packet not received complete
@ -410,6 +415,7 @@ int ObMysqlProtocolProcessor::process_fragment_mysql_packet(
int ObMysqlProtocolProcessor::process_one_mysql_packet(
ObMysqlPktContext &context,
obmysql::ObPacketRecordWrapper *pkt_rec_wrapper,
ObICSMemPool& pool,
const int64_t actual_data_len,
void *&ipacket,
@ -468,6 +474,9 @@ int ObMysqlProtocolProcessor::process_one_mysql_packet(
// no need set seq again
need_decode_more = false;
ipacket = raw_pkt;
if (OB_NOT_NULL(pkt_rec_wrapper) && pkt_rec_wrapper->enable_proto_dia()) {
pkt_rec_wrapper->record_recieve_mysql_packet(*raw_pkt);
}
LOG_DEBUG("recevie one mysql packet complete", K(context), KPC(raw_pkt),
K(total_data_len), K(actual_data_len));
}
@ -489,6 +498,7 @@ int ObMysqlProtocolProcessor::process_one_mysql_packet(
int ObMysqlProtocolProcessor::process_mysql_packet(
ObMysqlPktContext &context,
obmysql::ObPacketRecordWrapper *pkt_rec_wrapper,
ObICSMemPool& pool,
void *&ipacket,
bool &need_decode_more) {
@ -501,9 +511,13 @@ int ObMysqlProtocolProcessor::process_mysql_packet(
} else {
int64_t data_len = raw_pkt->get_clen();
const char *payload = raw_pkt->get_cdata();
if (OB_NOT_NULL(pkt_rec_wrapper) && pkt_rec_wrapper->enable_proto_dia()) {
pkt_rec_wrapper->record_recieve_mysql_pkt_fragment(raw_pkt->get_clen());
}
if (FALSE_IT(context.payload_len_ = data_len)) {
// impossible
} else if (OB_FAIL(process_one_mysql_packet(context, pool, data_len, ipacket, need_decode_more))) {
} else if (OB_FAIL(process_one_mysql_packet(context, pkt_rec_wrapper,
pool, data_len, ipacket, need_decode_more))) {
LOG_ERROR("fail to process one mysql packet", K(context), K(need_decode_more), K(ret));
} else {
if (need_decode_more) {
@ -520,6 +534,7 @@ int ObMysqlProtocolProcessor::process_mysql_packet(
context.payload_len_ = 0;
}
} else {
// nothing
context.reset();
}

View File

@ -16,6 +16,7 @@
#include "lib/ob_define.h"
#include "rpc/obmysql/ob_mysql_packet.h"
#include "rpc/obmysql/ob_virtual_cs_protocol_processor.h"
#include "rpc/obmysql/ob_packet_record.h"
namespace oceanbase
{
@ -57,9 +58,12 @@ private:
void *&ipacket, bool &need_decode_more, int64_t &pos);
int process_mysql_packet(ObMysqlPktContext &context,
obmysql::ObPacketRecordWrapper *pkt_rec_wrapper,
ObICSMemPool& pool,
void *&ipacket, bool &need_decode_more);
int process_one_mysql_packet(ObMysqlPktContext &context, ObICSMemPool& pool,
int process_one_mysql_packet(ObMysqlPktContext &context,
obmysql::ObPacketRecordWrapper *pkt_rec_wrapper,
ObICSMemPool& pool,
const int64_t actual_data_len, void *&ipacket,
bool &need_decode_more);
protected:

View File

@ -17,6 +17,8 @@
#include "rpc/ob_request.h"
#include "rpc/obmysql/ob_mysql_util.h"
#include "rpc/obmysql/ob_mysql_packet.h"
#include "rpc/obmysql/ob_packet_record.h"
#include "rpc/obmysql/obsm_struct.h"
using namespace oceanbase::common;
@ -70,6 +72,9 @@ static int build_compressed_packet(ObEasyBuffer &src_buf,
if (OB_ISNULL(context.send_buf_)) {
ret = OB_INVALID_ARGUMENT;
SERVER_LOG(WARN, "send_buf_ is null", K(context), K(ret));
} else if (OB_ISNULL(context.conn_)) {
ret = OB_INVALID_ARGUMENT;
SERVER_LOG(WARN, "conn_ is null", K(context), K(ret));
} else {
ObEasyBuffer dst_buf(*context.send_buf_);
const int64_t comp_buf_size = dst_buf.write_avail_size() - OB_MYSQL_COMPRESSED_HEADER_SIZE;
@ -111,6 +116,10 @@ static int build_compressed_packet(ObEasyBuffer &src_buf,
static_cast<int32_t>(len_before_compress), pos))) {
SERVER_LOG(WARN, "failed to store_int3", K(ret));
} else {
if (context.conn_->pkt_rec_wrapper_.enable_proto_dia()) {
context.conn_->pkt_rec_wrapper_.end_seal_comp_pkt(
static_cast<uint32_t>(dst_data_size), context.seq_);
}
SERVER_LOG(DEBUG, "succ to build compressed pkt", "comp_len", dst_data_size,
"comp_seq", context.seq_, K(len_before_compress), K(next_compress_size),
K(src_buf), K(dst_buf), K(context));

View File

@ -29,6 +29,10 @@ namespace rpc
{
class ObRequest;
}
namespace observer
{
class ObSMConnection;
}
namespace obmysql
{
@ -281,6 +285,7 @@ public:
easy_buf_t *send_buf_;
char *last_pkt_pos_;//proxy last pkt(error+ok, eof+ok, ok)'s pos in orig_ezbuf, default is null
uint32_t sessid_;
observer::ObSMConnection *conn_;
private:
DISALLOW_COPY_AND_ASSIGN(ObCompressionContext);

View File

@ -0,0 +1,124 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#define USING_LOG_PREFIX RPC_OBMYSQL
#include "rpc/obmysql/ob_packet_record.h"
using namespace oceanbase::common;
using namespace oceanbase::obmysql;
namespace oceanbase
{
namespace observer{
bool __attribute__((weak)) enable_proto_dia()
{
return false;
}
}
namespace obmysql
{
static const char* pkt_type_name[13] =
{
"INVALID_PKT",
"PKT_MYSQL", // 1 -> mysql packet;
"PKT_OKP", // 2 -> okp;
"PKT_ERR", // 3 -> error packet;
"PKT_EOF", // 4 -> eof packet;
"PKT_ROW", // 5 -> row packet;
"PKT_FIELD", // 6 -> field packet;
"PKT_PIECE", // 7 -> piece packet;
"PKT_STR", // 8 -> string packet;
"PKT_PREPARE", // 9 -> prepare packet;
"PKT_RESHEAD", // 10 -> result header packet
"PKT_PREXEC", // 11 -> prepare execute packet;
"PKT_END" // 12 -> end of packet type
};
int64_t ObPacketRecord::to_string(char *buf, const int64_t buf_len) const
{
int64_t pos = 0;
J_OBJ_START();
if (is_send_record()) {
databuff_printf(buf, buf_len, pos, "send:");
if (obp_mysql_header_.is_com_pkt_valid()) {
databuff_printf(buf, buf_len, pos, "obp_compess_header_");
J_OBJ_START();
J_KV("com_len", obp_mysql_header_.com_len_, "com_seq", obp_mysql_header_.com_seq_);
J_OBJ_END();
J_COMMA();
}
if (obp20_header_.is_valid()) {
J_KV(K(obp20_header_));
J_COMMA();
}
databuff_printf(buf, buf_len, pos, "obp_mysql_header_");
J_OBJ_START();
if (obp_mysql_header_.type_ == static_cast<uint8_t>(ObMySQLPacketType::PKT_ROW)
|| obp_mysql_header_.type_ == static_cast<uint8_t>(ObMySQLPacketType::PKT_FIELD)) {
J_KV("pkt_num_", obp_mysql_header_.mysql_header_.pkt_num_,"seq_", obp_mysql_header_.seq_);
} else {
J_KV("len_", obp_mysql_header_.mysql_header_.len_, "seq_", obp_mysql_header_.seq_);
}
J_OBJ_END();
J_COMMA();
J_KV("pkt_name", pkt_type_name[obp_mysql_header_.type_], K(obp_mysql_header_.is_send_));
} else {
databuff_printf(buf, buf_len, pos, "receive:");
if (obp_mysql_header_.is_com_pkt_valid()) {
databuff_printf(buf, buf_len, pos, "obp_compess_header_");
J_OBJ_START();
J_KV("com_len", obp_mysql_header_.com_len_, "com_seq", obp_mysql_header_.com_seq_);
J_OBJ_END();
J_COMMA();
}
if (obp20_header_.is_valid()) {
J_KV(K(obp20_header_));
J_COMMA();
}
databuff_printf(buf, buf_len, pos, "obp_mysql_header_");
J_OBJ_START();
J_KV("len_", obp_mysql_header_.mysql_header_.len_,
"rec_", obp_mysql_header_.rec_, "seq_", obp_mysql_header_.seq_);
J_OBJ_END();
J_COMMA();
J_KV(K(obp_mysql_header_.type_), K(obp_mysql_header_.is_send_));
}
J_OBJ_END();
return pos;
}
int64_t ObPacketRecordWrapper::to_string(char *buf, int64_t buf_len) const
{
int64_t pos = 0;
J_ARRAY_START();
J_KV(K(start_pkt_pos_), K(cur_pkt_pos_));
if (cur_pkt_pos_ > 0) {
J_COMMA();
}
int64_t start = 0;
if (cur_pkt_pos_-REC_BUF_SIZE > 0) {
start = cur_pkt_pos_-REC_BUF_SIZE;
}
for (int64_t index = start; (index < cur_pkt_pos_); index++) {
databuff_printf(buf, buf_len, pos, "pkt_rec[%ld]:", index);
BUF_PRINTO(pkt_rec_[index % REC_BUF_SIZE]);
if (index != cur_pkt_pos_-1) {
J_COMMA();
}
}
J_ARRAY_END();
return pos;
}
} // end of namespace obmysql
} // end of namespace oceanbase

View File

@ -0,0 +1,284 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#ifndef _OB_MYSQL_OB_PACKET_RECORD_H_
#define _OB_MYSQL_OB_PACKET_RECORD_H_
#include "rpc/obmysql/ob_mysql_packet.h"
#include "rpc/obmysql/ob_2_0_protocol_struct.h"
namespace oceanbase
{
namespace observer{
bool __attribute__((weak)) enable_proto_dia();
}
namespace obmysql
{
struct ResRecordFlags {
uint8_t is_send_: 1; // 0-send, 1-receive
uint8_t processed_: 1; // 请求处理结束,发送包后将会标记该位。
uint8_t reservered_: 8; // 其余位用于特殊标记
};
struct Obp20Header {
uint32_t payload_len_; // 4byte
Ob20ProtocolFlags flag_; // 4byte
int32_t req_id_; // 4byte
uint8_t pkt_seq_; // 1byte
uint16_t ext_flags_; // 2byte
Obp20Header() {
payload_len_ = 0;
flag_.flags_ = 0;
pkt_seq_ = 0;
ext_flags_ = 0;
req_id_ = 0;
}
bool is_valid() const {
return req_id_ != 0;
}
~Obp20Header() {}
TO_STRING_KV(K_(payload_len), K_(pkt_seq), K_(req_id), K_(flag_.flags), K_(ext_flags));
};//12byte
/*
// for send packet
// 0-> mysql packet; 1->okp;
// 2->error packet; 3->eof packet
// 4-> row packet; 5-> field packet;
// 6->piece packet; 7-> string packet;
// 8-> prepare packet; 9 ->result header packet
// 10-> prepare execute packet;
// for recieve packet
this field represents packet command
*/
struct ObpMysqHeader {
union {
uint32_t len_;
uint32_t pkt_num_; // 表示row packet/feild packet的数量。
} mysql_header_;
uint32_t rec_; // 表示目前收到多少byte的mysql包。
uint32_t com_len_; // compress head len
uint8_t seq_;
uint8_t type_;
uint8_t com_seq_; // compress head sequence
uint8_t is_send_;
ObpMysqHeader() {
rec_ = 0;
seq_ = 0;
mysql_header_.len_ = 0;
}
~ObpMysqHeader() {}
bool is_com_pkt_valid() const {
return com_len_ != 0 && com_seq_ != 0;
}
TO_STRING_KV(K_(mysql_header_.len), K_(rec), K_(seq));
}; // 16byte
class ObPacketRecord
{
public:
ObPacketRecord() {
obp_mysql_header_.type_ = 0;
obp_mysql_header_.is_send_ = 0;
}
~ObPacketRecord() {}
//for mysql fragment
inline void record_recieve_mysql_pkt_fragment(int32_t rec) __restrict__ {
obp_mysql_header_.rec_ += rec;
}
//for mysql fragment end
// for mysql protocol
inline void record_recieve_mysql_packet(ObMySQLRawPacket &__restrict__ pkt) __restrict__
{
obp_mysql_header_.mysql_header_.len_ = pkt.get_pkt_len();
obp_mysql_header_.seq_ = pkt.get_seq();
obp_mysql_header_.type_ = static_cast<uint8_t>(pkt.get_cmd());
obp_mysql_header_.is_send_ = 0;
}
inline void record_send_mysql_packet(ObMySQLPacket &__restrict__ pkt, int32_t len) __restrict__
{
if (pkt.get_mysql_packet_type() == ObMySQLPacketType::PKT_ROW ||
pkt.get_mysql_packet_type() == ObMySQLPacketType::PKT_FIELD) {
obp_mysql_header_.mysql_header_.pkt_num_++;
} else {
obp_mysql_header_.mysql_header_.len_ = len;
}
obp_mysql_header_.seq_ = pkt.get_seq();
obp_mysql_header_.type_ = static_cast<uint8_t>(pkt.get_mysql_packet_type());
obp_mysql_header_.is_send_ = 1;
}
// for mysql protocol end
// for ob20 protocol
inline void record_send_obp20_packet(uint32_t payload_len, Ob20ProtocolFlags flag,
uint8_t pkt_seq, uint16_t ext_flags,
int32_t req_id, uint32_t com_len, uint8_t com_seq)
{
obp20_header_.payload_len_ = payload_len;
obp20_header_.flag_ = flag;
obp20_header_.pkt_seq_ = pkt_seq;
obp20_header_.req_id_ = req_id;
obp20_header_.ext_flags_ = ext_flags;
obp_mysql_header_.com_len_ = com_len;
obp_mysql_header_.com_seq_ = com_seq;
}
inline void record_recieve_obp20_packet(Ob20Packet& obp20_pkt)
{
obp20_header_.payload_len_ = obp20_pkt.get_payload_len();
obp20_header_.flag_ = obp20_pkt.get_flags();
obp20_header_.pkt_seq_ = obp20_pkt.get_seq();
obp20_header_.req_id_ = obp20_pkt.get_request_id();
obp20_header_.ext_flags_ = 0;
obp_mysql_header_.com_len_ = obp20_pkt.get_comp_len();
obp_mysql_header_.com_seq_ = obp20_pkt.get_comp_seq();
}
// for ob20 protocol end
// for compress mysql protocol
inline void record_send_comp_packet(uint32_t com_len, uint8_t com_seq) __restrict__ {
obp_mysql_header_.com_len_ = com_len;
obp_mysql_header_.com_seq_ = com_seq;
}
inline void record_recieve_comp_packet(ObMySQLCompressedPacket &com_pkt) __restrict__ {
obp_mysql_header_.com_len_ = com_pkt.get_comp_len();
obp_mysql_header_.com_seq_ = com_pkt.get_comp_seq();
}
// for compress mysql protocol end
inline bool is_send_record() const __restrict__ {
return obp_mysql_header_.is_send_ == 1;
}
inline void set_packet_type(ObMySQLPacketType type) __restrict__ {
obp_mysql_header_.type_ = static_cast<uint8_t>(type);
}
int64_t to_string(char *buf, const int64_t buf_len) const;
Obp20Header obp20_header_; // 16 byte
ObpMysqHeader obp_mysql_header_; // 16 byte
}__attribute((aligned(32)));; // end of class ObPacketRecord
class ObPacketRecordWrapper {
public:
static const int64_t REC_BUF_SIZE = 32;
ObPacketRecordWrapper() {
start_pkt_pos_ = 0;
cur_pkt_pos_ = 0;
last_type_ = obmysql::ObMySQLPacketType::INVALID_PKT;
enable_proto_dia_ = false;
}
~ObPacketRecordWrapper() {}
void init() {
start_pkt_pos_ = 0;
cur_pkt_pos_ = 0;
last_type_ = obmysql::ObMySQLPacketType::INVALID_PKT;
enable_proto_dia_ = observer::enable_proto_dia();
}
int64_t to_string(char *buf, int64_t buf_len) const;
// for 20 protocol
inline void begin_seal_obp20_pkt() { start_pkt_pos_ = cur_pkt_pos_; }
inline void end_seal_obp20_pkt(uint32_t payload_len, obmysql::Ob20ProtocolFlags flag,
uint8_t pkt_seq, uint16_t ext_flags, int32_t req_id,
uint32_t com_len, uint8_t com_seq)
{
for (int64_t i = start_pkt_pos_; i < cur_pkt_pos_; i++) {
int64_t idx = i % ObPacketRecordWrapper::REC_BUF_SIZE;
obmysql::ObPacketRecord& rec = pkt_rec_[idx];
rec.record_send_obp20_packet(payload_len, flag, pkt_seq,
ext_flags, req_id, com_len, com_seq);
}
}
inline void record_recieve_obp20_packet(Ob20Packet &obp20_pkt,
obmysql::ObMySQLRawPacket &pkt)
{
int64_t idx = cur_pkt_pos_ % ObPacketRecordWrapper::REC_BUF_SIZE;
obmysql::ObPacketRecord& rec = pkt_rec_[idx];
rec.record_recieve_obp20_packet(obp20_pkt);
rec.record_recieve_mysql_packet(pkt);
cur_pkt_pos_++;
}
// for 20 protocol end
// for compress protocol
inline void begin_seal_comp_pkt() { start_pkt_pos_ = cur_pkt_pos_; }
inline void end_seal_comp_pkt(uint32_t com_len, uint8_t com_seq)
{
for (int64_t i = start_pkt_pos_; i < cur_pkt_pos_; i++) {
int64_t idx = i % ObPacketRecordWrapper::REC_BUF_SIZE;
obmysql::ObPacketRecord& rec = pkt_rec_[idx];
rec.record_send_comp_packet(com_len, com_seq);
}
}
void record_recieve_comp_packet(ObMySQLCompressedPacket &com_pkt,
obmysql::ObMySQLRawPacket &pkt)
{
int64_t idx = cur_pkt_pos_ % ObPacketRecordWrapper::REC_BUF_SIZE;
obmysql::ObPacketRecord& rec = pkt_rec_[idx];
rec.record_recieve_comp_packet(com_pkt);
rec.record_recieve_mysql_packet(pkt);
cur_pkt_pos_++;
}
// for compress protocol end
// for mysql protocol
inline void record_send_mysql_pkt(obmysql::ObMySQLPacket &__restrict__ pkt, int32_t len) __restrict__
{
if (pkt.get_mysql_packet_type() == last_type_) {
// do nothing
} else {
cur_pkt_pos_++;
}
int64_t idx = (cur_pkt_pos_-1) % ObPacketRecordWrapper::REC_BUF_SIZE;
pkt_rec_[idx].record_send_mysql_packet(pkt, len);
last_type_ = pkt.get_mysql_packet_type();
}
inline void record_recieve_mysql_packet(obmysql::ObMySQLRawPacket &__restrict__ pkt) __restrict__
{
int64_t idx = cur_pkt_pos_ % ObPacketRecordWrapper::REC_BUF_SIZE;
pkt_rec_[idx].record_recieve_mysql_packet(pkt);
cur_pkt_pos_++;
}
inline void record_recieve_mysql_pkt_fragment(int32_t recive) __restrict__
{
int64_t idx = cur_pkt_pos_ % ObPacketRecordWrapper::REC_BUF_SIZE;
pkt_rec_[idx].record_recieve_mysql_pkt_fragment(recive);
}
// for mysql protocol end
inline bool enable_proto_dia() {
return enable_proto_dia_;
}
public:
obmysql::ObPacketRecord pkt_rec_[REC_BUF_SIZE];
uint32_t start_pkt_pos_;
uint32_t cur_pkt_pos_;
obmysql::ObMySQLPacketType last_type_;
bool enable_proto_dia_;
};
} // end of namespace obmysql
} // end of namespace oceanbase
#endif /* _OB_MYSQL_OB_PACKET_RECORD_H_ */

View File

@ -17,6 +17,8 @@
#include "rpc/obmysql/ob_mysql_request_utils.h"
#include "rpc/ob_packet.h"
#include "lib/lock/ob_latch.h"
#include "rpc/obmysql/ob_packet_record.h"
#include "rpc/obmysql/ob_2_0_protocol_struct.h"
namespace oceanbase
{
@ -65,6 +67,7 @@ public:
proxy_version_ = 0;
group_id_ = 0;
client_cs_type_ = 0;
pkt_rec_wrapper_.init();
}
obmysql::ObCompressType get_compress_type() {
@ -180,6 +183,7 @@ public:
uint64_t proxy_version_;
int32_t group_id_;
int32_t client_cs_type_;
obmysql::ObPacketRecordWrapper pkt_rec_wrapper_;
};
} // end of namespace observer
} // end of namespace oceanbase

View File

@ -41,6 +41,7 @@ public:
inline uint8_t get_field_count() const { return field_count_; }
inline uint16_t get_warning_count() const { return warning_count_; }
inline ObServerStatusFlags get_server_status() const { return server_status_; }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_EOF; }
virtual int64_t to_string(char *buf, const int64_t buf_len) const;
private:
DISALLOW_COPY_AND_ASSIGN(OMPKEOF);

View File

@ -44,6 +44,7 @@ public:
inline common::ObString get_sql_state() const { return sqlstate_; }
inline common::ObString get_message() const { return message_; }
virtual int64_t to_string(char *buf, const int64_t buf_len) const;
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_ERR; }
private:

View File

@ -27,6 +27,7 @@ class OMPKField
public:
explicit OMPKField(ObMySQLField &field);
virtual ~OMPKField() { }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_FIELD; }
virtual int serialize(char *buffer, int64_t len, int64_t &pos) const;
private:

View File

@ -63,6 +63,7 @@ public:
inline const common::ObIArray<ObStringKV> &get_system_vars() const { return system_vars_; }
inline const common::ObIArray<ObStringKV> &get_user_vars() const { return user_vars_; }
inline ObMySQLCapabilityFlags get_capability() const { return capability_; }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_OKP; }
virtual int64_t to_string(char *buf, const int64_t buf_len) const;
private:

View File

@ -45,6 +45,7 @@ public:
virtual int serialize(char *buffer, int64_t len, int64_t &pos) const;
virtual int64_t get_serialize_size() const;
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_PIECE; }
inline void set_piece_mode(int8_t piece_mode) { piece_mode_ = piece_mode; }
inline void set_data(common::ObString &data) { data_ = data; }

View File

@ -57,6 +57,7 @@ public:
inline void set_param_num(const uint16_t num) { param_num_ = num; }
inline void set_warning_count(const uint16_t count) { warning_count_ = count; }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_PREPARE; }
private:
uint8_t status_;

View File

@ -61,6 +61,7 @@ public:
inline void set_extend_flag(ObServerExtendFlag flag) { extend_flag_ = flag; }
inline void set_has_result_set(int8_t has_result) { has_result_set_ = has_result; }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_PREXEC; }
private:
ObServerExtendFlag extend_flag_;

View File

@ -40,6 +40,7 @@ public:
{
return field_count_;
}
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_RESHEAD; }
private:
DISALLOW_COPY_AND_ASSIGN(OMPKResheader);

View File

@ -26,6 +26,7 @@ class OMPKRow : public ObMySQLPacket
public:
explicit OMPKRow(const ObMySQLRow &row);
virtual ~OMPKRow() { }
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_ROW; }
virtual int serialize(char *buffer, int64_t len, int64_t &pos) const;
private:

View File

@ -44,6 +44,7 @@ public:
}
return ret;
}
inline ObMySQLPacketType get_mysql_packet_type() { return ObMySQLPacketType::PKT_STR; }
VIRTUAL_TO_STRING_KV("header", hdr_, K_(str));

View File

@ -81,7 +81,6 @@ oblib_addtest(queue/test_priority_queue.cpp)
oblib_addtest(random/test_mysql_random.cpp)
oblib_addtest(random/test_random.cpp)
oblib_addtest(rc/test_context.cpp)
oblib_addtest(regex/test_regex.cpp)
oblib_addtest(resource/test_resource_mgr.cpp)
#oblib_addtest(restore/test_storage_file.cpp)
#oblib_addtest(restore/test_storage_oss.cpp)

View File

@ -1,622 +0,0 @@
/**
* Copyright (c) 2021 OceanBase
* OceanBase CE is licensed under Mulan PubL v2.
* You can use this software according to the terms and conditions of the Mulan PubL v2.
* You may obtain a copy of Mulan PubL v2 at:
* http://license.coscl.org.cn/MulanPubL-2.0
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PubL v2 for more details.
*/
#include <gtest/gtest.h>
#include "lib/ob_define.h"
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include "lib/regex/regex/regalone.h"
#include "lib/regex/regex/ob_regex.h"
#include <assert.h>
#include "test_regex.ih"
#include "lib/utility/ob_macro_utils.h"
using namespace oceanbase::common;
#if 0
int debug = 0;
int line = 0;
int status = 0;
int copts = OB_REG_EXTENDED;
int eopts = 0;
ob_regoff_t startoff = 0;
ob_regoff_t endoff = 0;
//extern void regprint();
/*
- split - divide a string into fields, like awk split()
= int split(char *string, char *fields[], int nfields, char *sep);
*/
int /* number of fields, including overflow */
split(char *string,
char *fields[], /* list is not NULL-terminated */
int nfields, /* number of entries available in fields[] */
char *sep /* "" white, "c" single char, "ab" [ab]+ */
)
{
register char *p = string;
register char c; /* latest character */
register char sepc = sep[0];
register char sepc2;
register int fn;
register char **fp = fields;
register char *sepp;
register int trimtrail;
/* white space */
if (sepc == '\0') {
while ((c = *p++) == ' ' || c == '\t')
continue;
p--;
trimtrail = 1;
static char static_sep[5] = " \t";
sep = static_sep; /* note, code below knows this is 2 long */
sepc = ' ';
} else
trimtrail = 0;
sepc2 = sep[1]; /* now we can safely pick this up */
/* catch empties */
if (*p == '\0')
return(0);
/* single separator */
if (sepc2 == '\0') {
fn = nfields;
for (;;) {
*fp++ = p;
fn--;
if (fn == 0)
break;
while ((c = *p++) != sepc)
if (c == '\0')
return(nfields - fn);
*(p-1) = '\0';
}
/* we have overflowed the fields vector -- just count them */
fn = nfields;
for (;;) {
while ((c = *p++) != sepc)
if (c == '\0')
return(fn);
fn++;
}
/* not reached */
}
/* two separators */
if (sep[2] == '\0') {
fn = nfields;
for (;;) {
*fp++ = p;
fn--;
while ((c = *p++) != sepc && c != sepc2)
if (c == '\0') {
if (trimtrail && **(fp-1) == '\0')
fn++;
return(nfields - fn);
}
if (fn == 0)
break;
*(p-1) = '\0';
while ((c = *p++) == sepc || c == sepc2)
continue;
p--;
}
/* we have overflowed the fields vector -- just count them */
fn = nfields;
while (c != '\0') {
while ((c = *p++) == sepc || c == sepc2)
continue;
p--;
fn++;
while ((c = *p++) != '\0' && c != sepc && c != sepc2)
continue;
}
/* might have to trim trailing white space */
if (trimtrail) {
p--;
while ((c = *--p) == sepc || c == sepc2)
continue;
p++;
if (*p != '\0') {
if (fn == nfields+1)
*p = '\0';
fn--;
}
}
return(fn);
}
/* n separators */
fn = 0;
for (;;) {
if (fn < nfields)
*fp++ = p;
fn++;
for (;;) {
c = *p++;
if (c == '\0')
return(fn);
sepp = sep;
while ((sepc = *sepp++) != '\0' && sepc != c)
continue;
if (sepc != '\0') /* it was a separator */
break;
}
if (fn < nfields)
*(p-1) = '\0';
for (;;) {
c = *p++;
sepp = sep;
while ((sepc = *sepp++) != '\0' && sepc != c)
continue;
if (sepc == '\0') /* it wasn't a separator */
break;
}
p--;
}
/* not reached */
}
/*
- regress - main loop of regression test
== bool regress(FILE *in);
*/
bool
regress(FILE *in)
{
char inbuf[1000];
# define MAXF 10
char *f[MAXF];
int nf;
int i;
char erbuf[100];
size_t ne;
const char *badpat = "invalid regular expression";
# define SHORT 10
const wchar_t *bpname = "OB_REG_BADPAT";
ob_regex_t re;
char sep[5] = "\t\t";
while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
line++;
if (inbuf[0] == '#' || inbuf[0] == '\n')
continue; /* NOTE CONTINUE */
inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
if (debug)
fprintf(stdout, "%d:\n", line);
nf = split(inbuf, f, MAXF, sep);
if (nf < 3) {
fprintf(stderr, "bad input, line %d\n", line);
return false;
}
for (i = 0; i < nf; i++)
if (strcmp(f[i], "\"\"") == 0)
f[i][0] = '\0';
//f[i] = "";
if (nf <= 3)
f[3] = NULL;
if (nf <= 4)
f[4] = NULL;
try_case(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
if (opt('&', f[1])) /* try with either type of RE */
try_case(f[0], f[1], f[2], f[3], f[4],
options('c', f[1]) &~ OB_REG_EXTENDED);
}
ne = ob_regerror(OB_REG_BADPAT, (ob_regex_t *)NULL, erbuf, sizeof(erbuf));
if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
erbuf, badpat);
status = 1;
}
ne = ob_regerror(OB_REG_BADPAT, (ob_regex_t *)NULL, erbuf, (size_t)SHORT);
if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
ne != strlen(badpat)+1) {
fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
erbuf, SHORT-1, badpat);
status = 1;
}
ne = ob_regerror(OB_REG_ITOA|OB_REG_BADPAT, (ob_regex_t *)NULL, erbuf, sizeof(erbuf));
if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname)+1) {
fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
erbuf, bpname);
status = 1;
}
re.re_endp = bpname;
ne = ob_regerror(OB_REG_ATOI, &re, erbuf, sizeof(erbuf));
if (atoi(erbuf) != (int)OB_REG_BADPAT) {
fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
erbuf, (long)OB_REG_BADPAT);
status = 1;
} else if (ne != strlen(erbuf)+1) {
fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
erbuf, (long)OB_REG_BADPAT);
status = 1;
}
return 0 == status;
}
/*
- try_case - try it, and report on problems
== void try_case(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
*/
void
try_case(char *f0,
char *f1,
char *f2,
char *f3,
char *f4,
int opts /* may not match f1 */
)
{
ob_regex_t re;
# define NSUBS 10
ob_regmatch_t subs[NSUBS];
# define NSHOULD 15
char *should[NSHOULD];
int nshould;
char erbuf[100];
int err;
int len;
const char *type = (opts & OB_REG_EXTENDED) ? "ERE" : "BRE";
register int i;
char *grump;
char f0copy[1000];
char f2copy[1000];
char sep[5] = ",";
strcpy(f0copy, f0);
re.re_endp = (opts&OB_REG_PEND) ? f0copy + strlen(f0copy) : NULL;
fixstr(f0copy);
err = ob_regcomp(&re, f0copy, opts, &ob_charset_utf8mb4_general_ci);
if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
/* unexpected error or wrong error */
len = (int) ob_regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "%d: %s error %s, %d/%d `%s'\n",
line, type, eprint(err), len,
(int) sizeof(erbuf), erbuf);
status = 1;
} else if (err == 0 && opt('C', f1)) {
/* unexpected success */
fprintf(stderr, "%d: %s should have given OB_REG_%s\n",
line, type, f2);
status = 1;
err = 1; /* so we won't try regexec */
}
if (err != 0) {
ob_regfree(&re);
return;
}
strcpy(f2copy, f2);
fixstr(f2copy);
if (options('e', f1)&OB_REG_STARTEND) {
if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
fprintf(stderr, "%d: bad STARTEND syntax\n", line);
subs[0].rm_so = strchr(f2, '(') - f2 + 1;
subs[0].rm_eo = strchr(f2, ')') - f2;
}
err = ob_regexec(&re, f2copy, NSUBS, subs, options('e', f1));
if (err != 0 && (f3 != NULL || err != OB_REG_NOMATCH)) {
/* unexpected error or wrong error */
len = (int) ob_regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "%d: %s exec error %s, %d/%d `%s'\n",
line, type, eprint(err), len,
(int) sizeof(erbuf), erbuf);
status = 1;
} else if (err != 0) {
/* nothing more to check */
} else if (f3 == NULL) {
/* unexpected success */
fprintf(stderr, "%d: %s exec should have failed\n",
line, type);
status = 1;
err = 1; /* just on principle */
} else if (opts&OB_REG_NOSUB) {
/* nothing more to check */
} else if ((grump = check(f2, subs[0], f3)) != NULL) {
fprintf(stderr, "%d: %s %s\n", line, type, grump);
status = 1;
err = 1;
}
if (err != 0 || f4 == NULL) {
ob_regfree(&re);
return;
}
for (i = 1; i < NSHOULD; i++)
should[i] = NULL;
nshould = split(f4, should+1, NSHOULD-1, sep);
if (nshould == 0) {
nshould = 1;
should[1][0] = '\0';
//should[1] = "";
}
for (i = 1; i < NSUBS; i++) {
grump = check(f2, subs[i], should[i]);
if (grump != NULL) {
fprintf(stderr, "%d: %s $%d %s\n", line,
type, i, grump);
status = 1;
err = 1;
}
}
ob_regfree(&re);
}
/*
- options - pick options out of a regression-test string
== int options(int type, char *s);
*/
int
options(int type, /* 'c' compile, 'e' exec */
char *s)
{
register char *p;
register int o = (type == 'c') ? copts : eopts;
register const char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
for (p = s; *p != '\0'; p++)
if (strchr(legal, *p) != NULL)
switch (*p) {
case 'b':
o &= ~OB_REG_EXTENDED;
break;
case 'i':
o |= OB_REG_ICASE;
break;
case 's':
o |= OB_REG_NOSUB;
break;
case 'n':
o |= OB_REG_NEWLINE;
break;
case 'm':
o &= ~OB_REG_EXTENDED;
o |= OB_REG_NOSPEC;
break;
case 'p':
o |= OB_REG_PEND;
break;
case '^':
o |= OB_REG_NOTBOL;
break;
case '$':
o |= OB_REG_NOTEOL;
break;
case '#':
o |= OB_REG_STARTEND;
break;
case 't': /* trace */
o |= OB_REG_TRACE;
break;
case 'l': /* force long representation */
o |= OB_REG_LARGE;
break;
case 'r': /* force backref use */
o |= OB_REG_BACKR;
break;
}
return(o);
}
/*
- opt - is a particular option in a regression string?
== int opt(int c, char *s);
*/
int /* predicate */
opt(int c, char *s)
{
return(strchr(s, c) != NULL);
}
/*
- fixstr - transform magic characters in strings
== void fixstr(register char *p);
*/
void
fixstr(register char *p)
{
if (p == NULL)
return;
for (; *p != '\0'; p++)
if (*p == 'N')
*p = '\n';
else if (*p == 'T')
*p = '\t';
else if (*p == 'S')
*p = ' ';
else if (*p == 'Z')
*p = '\0';
}
/*
- check - check a substring match
== char *check(char *str, ob_regmatch_t sub, char *should);
*/
char * /* NULL or complaint */
check(char *str, ob_regmatch_t sub, char *should)
{
register int len;
register int shlen;
register char *p;
static char grump[500];
register char *at = NULL;
if (should != NULL && strcmp(should, "-") == 0)
should = NULL;
if (should != NULL && should[0] == '@') {
at = should + 1;
should[0] = '\0';
}
/* check rm_so and rm_eo for consistency */
if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
(sub.rm_so != -1 && sub.rm_eo == -1) ||
(sub.rm_so != -1 && sub.rm_so < 0) ||
(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
(long)sub.rm_eo);
return(grump);
}
/* check for no match */
if (sub.rm_so == -1 && should == NULL)
return(NULL);
if (sub.rm_so == -1) {
static char ret_err_buf[50] = "did not match";
return(ret_err_buf);
}
/* check for in range */
if (sub.rm_eo > strlen(str)) {
sprintf(grump, "start %ld end %ld, past end of string",
(long)sub.rm_so, (long)sub.rm_eo);
return(grump);
}
len = (int)(sub.rm_eo - sub.rm_so);
shlen = (int)strlen(should);
p = str + sub.rm_so;
/* check for not supposed to match */
if (should == NULL) {
sprintf(grump, "matched `%.*s'", len, p);
return(grump);
}
/* check for wrong match */
if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
sprintf(grump, "matched `%.*s' instead", len, p);
return(grump);
}
if (shlen > 0)
return(NULL);
/* check null match in right place */
if (at == NULL)
return(NULL);
shlen = (int)strlen(at);
if (shlen == 0)
shlen = 1; /* force check for end-of-string */
if (strncmp(p, at, shlen) != 0) {
sprintf(grump, "matched null at `%.20s'", p);
return(grump);
}
return(NULL);
}
/*
- eprint - convert error number to name
== static char *eprint(int err);
*/
static char *
eprint(int err)
{
static char epbuf[100];
size_t len;
len = ob_regerror(OB_REG_ITOA|err, (ob_regex_t *)NULL, epbuf, sizeof(epbuf));
assert(len <= sizeof(epbuf));
UNUSED(len);
return(epbuf);
}
/*
- efind - convert error name to number
== static int efind(char *name);
*/
static int
efind(char *name)
{
static char efbuf[100];
//size_t n;
ob_regex_t re;
sprintf(efbuf, "OB_REG_%s", name);
assert(strlen(efbuf) < sizeof(efbuf));
re.re_endp = efbuf;
(void) ob_regerror(OB_REG_ATOI, &re, efbuf, sizeof(efbuf));
return(atoi(efbuf));
}
class ObRegexTest : public ::testing::Test
{
public:
ObRegexTest();
virtual ~ObRegexTest();
virtual void SetUp();
virtual void TearDown();
private:
// disallow copy
ObRegexTest(const ObRegexTest &other);
ObRegexTest& operator=(const ObRegexTest &other);
private:
// data members
};
ObRegexTest::ObRegexTest()
{
}
ObRegexTest::~ObRegexTest()
{
}
void ObRegexTest::SetUp()
{
}
void ObRegexTest::TearDown()
{
}
TEST_F(ObRegexTest, basic_test)
{
/*
- main - do the simple case, hand off to regress() for regression
*/
char test_filename[] = "regex/tests";
FILE *test_file = fopen(test_filename, "r");
if (NULL == test_file) {
fprintf(stderr, "fail to open file '%s'\n", test_filename);
} else {
ASSERT_TRUE(regress(test_file));
fclose(test_file);
}
}
#endif
int main(int argc, char **argv)
{
OB_LOGGER.set_log_level("INFO");
//ob_init_memory_pool();
::testing::InitGoogleTest(&argc,argv);
return RUN_ALL_TESTS();
}

View File

@ -1,19 +0,0 @@
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
extern "C" {
#endif
/* === main.c === */
bool regress(FILE *in);
void try_case(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
int options(int type, char *s);
int opt(int c, char *s);
void fixstr(register char *p);
char *check(char *str, ob_regmatch_t sub, char *should);
static char *eprint(int err);
static int efind(char *name);
#ifdef __cplusplus
}
#endif
/* ========= end header generated by ./mkh ========= */

View File

@ -1,479 +0,0 @@
# regular expression test set
# Lines are at least three fields, separated by one or more tabs. "" stands
# for an empty field. First field is an RE. Second field is flags. If
# C flag given, regcomp() is expected to fail, and the third field is the
# error name (minus the leading REG_).
#
# Otherwise it is expected to succeed, and the third field is the string to
# try matching it against. If there is no fourth field, the match is
# expected to fail. If there is a fourth field, it is the substring that
# the RE is expected to match. If there is a fifth field, it is a comma-
# separated list of what the subexpressions should match, with - indicating
# no match for that one. In both the fourth and fifth fields, a (sub)field
# starting with @ indicates that the (sub)expression is expected to match
# a null string followed by the stuff after the @; this provides a way to
# test where null strings match. The character `N' in REs and strings
# is newline, `S' is space, `T' is tab, `Z' is NUL.
#
# The full list of flags:
# - placeholder, does nothing
# b RE is a BRE, not an ERE
# & try it as both an ERE and a BRE
# C regcomp() error expected, third field is error name
# i REG_ICASE
# m ("mundane") REG_NOSPEC
# s REG_NOSUB (not really testable)
# n REG_NEWLINE
# ^ REG_NOTBOL
# $ REG_NOTEOL
# # REG_STARTEND (see below)
# p REG_PEND
#
# For REG_STARTEND, the start/end offsets are those of the substring
# enclosed in ().
# basics
a & a a
abc & abc abc
abc|de - abc abc
a|b|c - abc a
# parentheses and perversions thereof
a(b)c - abc abc
a\(b\)c b abc abc
a( C EPAREN
a( b a( a(
a\( - a( a(
a\( bC EPAREN
a\(b bC EPAREN
a(b C EPAREN
a(b b a(b a(b
# gag me with a right parenthesis -- 1003.2 goofed here (my fault, partly)
a) - a) a)
) - ) )
# end gagging (in a just world, those *should* give EPAREN)
a) b a) a)
a\) bC EPAREN
\) bC EPAREN
a()b - ab ab
a\(\)b b ab ab
# anchoring and REG_NEWLINE
^abc$ & abc abc
a^b - a^b
a^b b a^b a^b
a$b - a$b
a$b b a$b a$b
^ & abc @abc
$ & abc @
^$ & "" @
$^ - "" @
\($\)\(^\) b "" @
# stop retching, those are legitimate (although disgusting)
^^ - "" @
$$ - "" @
b$ & abNc
b$ &n abNc b
^b$ & aNbNc
^b$ &n aNbNc b
^$ &n aNNb @Nb
^$ n abc
^$ n abcN @
$^ n aNNb @Nb
\($\)\(^\) bn aNNb @Nb
^^ n^ aNNb @Nb
$$ n aNNb @NN
^a ^ a
a$ $ a
^a ^n aNb
^b ^n aNb b
a$ $n bNa
b$ $n bNa b
a*(^b$)c* - b b
a*\(^b$\)c* b b b
# certain syntax errors and non-errors
| C EMPTY
| b | |
* C BADRPT
* b * *
+ C BADRPT
? C BADRPT
"" &C EMPTY
() - abc @abc
\(\) b abc @abc
a||b C EMPTY
|ab C EMPTY
ab| C EMPTY
(|a)b C EMPTY
(a|)b C EMPTY
(*a) C BADRPT
(+a) C BADRPT
(?a) C BADRPT
({1}a) C BADRPT
\(\{1\}a\) bC BADRPT
(a|*b) C BADRPT
(a|+b) C BADRPT
(a|?b) C BADRPT
(a|{1}b) C BADRPT
^* C BADRPT
^* b * *
^+ C BADRPT
^? C BADRPT
^{1} C BADRPT
^\{1\} bC BADRPT
# metacharacters, backslashes
a.c & abc abc
a[bc]d & abd abd
a\*c & a*c a*c
a\\b & a\b a\b
a\\\*b & a\*b a\*b
a\bc & abc abc
a\ &C EESCAPE
a\\bc & a\bc a\bc
\{ bC BADRPT
a\[b & a[b a[b
a[b &C EBRACK
# trailing $ is a peculiar special case for the BRE code
a$ & a a
a$ & a$
a\$ & a
a\$ & a$ a$
a\\$ & a
a\\$ & a$
a\\$ & a\$
a\\$ & a\ a\
# back references, ugh
a\(b\)\2c bC ESUBREG
a\(b\1\)c bC ESUBREG
a\(b*\)c\1d b abbcbbd abbcbbd bb
a\(b*\)c\1d b abbcbd
a\(b*\)c\1d b abbcbbbd
^\(.\)\1 b abc
a\([bc]\)\1d b abcdabbd abbd b
a\(\([bc]\)\2\)*d b abbccd abbccd
a\(\([bc]\)\2\)*d b abbcbd
# actually, this next one probably ought to fail, but the spec is unclear
a\(\(b\)*\2\)*d b abbbd abbbd
# here is a case that no NFA implementation does right
\(ab*\)[ab]*\1 b ababaaa ababaaa a
# check out normal matching in the presence of back refs
\(a\)\1bcd b aabcd aabcd
\(a\)\1bc*d b aabcd aabcd
\(a\)\1bc*d b aabd aabd
\(a\)\1bc*d b aabcccd aabcccd
\(a\)\1bc*[ce]d b aabcccd aabcccd
^\(a\)\1b\(c\)*cd$ b aabcccd aabcccd
# ordinary repetitions
ab*c & abc abc
ab+c - abc abc
ab?c - abc abc
a\(*\)b b a*b a*b
a\(**\)b b ab ab
a\(***\)b bC BADRPT
*a b *a *a
**a b a a
***a bC BADRPT
# the dreaded bounded repetitions
{ & { {
{abc & {abc {abc
{1 C BADRPT
{1} C BADRPT
a{b & a{b a{b
a{1}b - ab ab
a\{1\}b b ab ab
a{1,}b - ab ab
a\{1,\}b b ab ab
a{1,2}b - aab aab
a\{1,2\}b b aab aab
a{1 C EBRACE
a\{1 bC EBRACE
a{1a C EBRACE
a\{1a bC EBRACE
a{1a} C BADBR
a\{1a\} bC BADBR
a{,2} - a{,2} a{,2}
a\{,2\} bC BADBR
a{,} - a{,} a{,}
a\{,\} bC BADBR
a{1,x} C BADBR
a\{1,x\} bC BADBR
a{1,x C EBRACE
a\{1,x bC EBRACE
a{300} C BADBR
a\{300\} bC BADBR
a{1,0} C BADBR
a\{1,0\} bC BADBR
ab{0,0}c - abcac ac
ab\{0,0\}c b abcac ac
ab{0,1}c - abcac abc
ab\{0,1\}c b abcac abc
ab{0,3}c - abbcac abbc
ab\{0,3\}c b abbcac abbc
ab{1,1}c - acabc abc
ab\{1,1\}c b acabc abc
ab{1,3}c - acabc abc
ab\{1,3\}c b acabc abc
ab{2,2}c - abcabbc abbc
ab\{2,2\}c b abcabbc abbc
ab{2,4}c - abcabbc abbc
ab\{2,4\}c b abcabbc abbc
((a{1,10}){1,10}){1,10} - a a a,a
# multiple repetitions
a** &C BADRPT
a++ C BADRPT
a?? C BADRPT
a*+ C BADRPT
a*? C BADRPT
a+* C BADRPT
a+? C BADRPT
a?* C BADRPT
a?+ C BADRPT
a{1}{1} C BADRPT
a*{1} C BADRPT
a+{1} C BADRPT
a?{1} C BADRPT
a{1}* C BADRPT
a{1}+ C BADRPT
a{1}? C BADRPT
a*{b} - a{b} a{b}
a\{1\}\{1\} bC BADRPT
a*\{1\} bC BADRPT
a\{1\}* bC BADRPT
# brackets, and numerous perversions thereof
a[b]c & abc abc
a[ab]c & abc abc
a[^ab]c & adc adc
a[]b]c & a]c a]c
a[[b]c & a[c a[c
a[-b]c & a-c a-c
a[^]b]c & adc adc
a[^-b]c & adc adc
a[b-]c & a-c a-c
a[b &C EBRACK
a[] &C EBRACK
a[1-3]c & a2c a2c
a[3-1]c &C ERANGE
a[1-3-5]c &C ERANGE
a[[.-.]--]c & a-c a-c
a[1- &C ERANGE
a[[. &C EBRACK
a[[.x &C EBRACK
a[[.x. &C EBRACK
a[[.x.] &C EBRACK
a[[.x.]] & ax ax
a[[.x,.]] &C ECOLLATE
a[[.one.]]b & a1b a1b
a[[.notdef.]]b &C ECOLLATE
a[[.].]]b & a]b a]b
a[[:alpha:]]c & abc abc
a[[:notdef:]]c &C ECTYPE
a[[: &C EBRACK
a[[:alpha &C EBRACK
a[[:alpha:] &C EBRACK
a[[:alpha,:] &C ECTYPE
a[[:]:]]b &C ECTYPE
a[[:-:]]b &C ECTYPE
a[[:alph:]] &C ECTYPE
a[[:alphabet:]] &C ECTYPE
[[:alnum:]]+ - -%@a0X- a0X
[[:alpha:]]+ - -%@aX0- aX
# 在字符集utf8mb4_general_ci中,'\t'不是[:blank:],因此这里只适配SS,不适配T
#[[:blank:]]+ - aSSTb SST
[[:blank:]]+ - aSSTb SS
[[:cntrl:]]+ - aNTb NT
[[:digit:]]+ - a019b 019
[[:graph:]]+ - Sa%bS a%b
[[:lower:]]+ - AabC ab
[[:print:]]+ - NaSbN aSb
[[:punct:]]+ - S%-&T %-&
[[:space:]]+ - aSNTb SNT
[[:upper:]]+ - aBCd BC
[[:xdigit:]]+ - p0f3Cq 0f3C
a[[=b=]]c & abc abc
a[[= &C EBRACK
a[[=b &C EBRACK
a[[=b= &C EBRACK
a[[=b=] &C EBRACK
a[[=b,=]] &C ECOLLATE
a[[=one=]]b & a1b a1b
# complexities
a(((b)))c - abc abc
a(b|(c))d - abd abd
a(b*|c)d - abbd abbd
# just gotta have one DFA-buster, of course
a[ab]{20} - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
# and an inline expansion in case somebody gets tricky
a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab] - aaaaabaaaabaaaabaaaab aaaaabaaaabaaaabaaaab
# and in case somebody just slips in an NFA...
a[ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab][ab](wee|week)(knights|night) - aaaaabaaaabaaaabaaaabweeknights aaaaabaaaabaaaabaaaabweeknights
# fish for anomalies as the number of states passes 32
12345678901234567890123456789 - a12345678901234567890123456789b 12345678901234567890123456789
123456789012345678901234567890 - a123456789012345678901234567890b 123456789012345678901234567890
1234567890123456789012345678901 - a1234567890123456789012345678901b 1234567890123456789012345678901
12345678901234567890123456789012 - a12345678901234567890123456789012b 12345678901234567890123456789012
123456789012345678901234567890123 - a123456789012345678901234567890123b 123456789012345678901234567890123
# and one really big one, beyond any plausible word width
1234567890123456789012345678901234567890123456789012345678901234567890 - a1234567890123456789012345678901234567890123456789012345678901234567890b 1234567890123456789012345678901234567890123456789012345678901234567890
# fish for problems as brackets go past 8
[ab][cd][ef][gh][ij][kl][mn] - xacegikmoq acegikm
[ab][cd][ef][gh][ij][kl][mn][op] - xacegikmoq acegikmo
[ab][cd][ef][gh][ij][kl][mn][op][qr] - xacegikmoqy acegikmoq
[ab][cd][ef][gh][ij][kl][mn][op][q] - xacegikmoqy acegikmoq
# subtleties of matching
abc & xabcy abc
a\(b\)?c\1d b acd
aBc i Abc Abc
a[Bc]*d i abBCcd abBCcd
0[[:upper:]]1 &i 0a1 0a1
0[[:lower:]]1 &i 0A1 0A1
a[^b]c &i abc
a[^b]c &i aBc
a[^b]c &i adc adc
[a]b[c] - abc abc
[a]b[a] - aba aba
[abc]b[abc] - abc abc
[abc]b[abd] - abd abd
a(b?c)+d - accd accd
(wee|week)(knights|night) - weeknights weeknights
(we|wee|week|frob)(knights|night|day) - weeknights weeknights
a[bc]d - xyzaaabcaababdacd abd
a[ab]c - aaabc abc
abc s abc abc
a* & b @b
# Let's have some fun -- try to match a C comment.
# first the obvious, which looks okay at first glance...
/\*.*\*/ - /*x*/ /*x*/
# but...
/\*.*\*/ - /*x*/y/*z*/ /*x*/y/*z*/
# okay, we must not match */ inside; try to do that...
/\*([^*]|\*[^/])*\*/ - /*x*/ /*x*/
/\*([^*]|\*[^/])*\*/ - /*x*/y/*z*/ /*x*/
# but...
/\*([^*]|\*[^/])*\*/ - /*x**/y/*z*/ /*x**/y/*z*/
# and a still fancier version, which does it right (I think)...
/\*([^*]|\*+[^*/])*\*+/ - /*x*/ /*x*/
/\*([^*]|\*+[^*/])*\*+/ - /*x*/y/*z*/ /*x*/
/\*([^*]|\*+[^*/])*\*+/ - /*x**/y/*z*/ /*x**/
/\*([^*]|\*+[^*/])*\*+/ - /*x****/y/*z*/ /*x****/
/\*([^*]|\*+[^*/])*\*+/ - /*x**x*/y/*z*/ /*x**x*/
/\*([^*]|\*+[^*/])*\*+/ - /*x***x/y/*z*/ /*x***x/y/*z*/
# subexpressions
.* - abc abc -
a(b)(c)d - abcd abcd b,c
a(((b)))c - abc abc b,b,b
a(b|(c))d - abd abd b,-
a(b*|c|e)d - abbd abbd bb
a(b*|c|e)d - acd acd c
a(b*|c|e)d - ad ad @d
a(b?)c - abc abc b
a(b?)c - ac ac @c
a(b+)c - abc abc b
a(b+)c - abbbc abbbc bbb
a(b*)c - ac ac @c
(a|ab)(bc([de]+)f|cde) - abcdef abcdef a,bcdef,de
# the regression tester only asks for 9 subexpressions
a(b)(c)(d)(e)(f)(g)(h)(i)(j)k - abcdefghijk abcdefghijk b,c,d,e,f,g,h,i,j
a(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)l - abcdefghijkl abcdefghijkl b,c,d,e,f,g,h,i,j,k
a([bc]?)c - abc abc b
a([bc]?)c - ac ac @c
a([bc]+)c - abc abc b
a([bc]+)c - abcc abcc bc
a([bc]+)bc - abcbc abcbc bc
a(bb+|b)b - abb abb b
a(bbb+|bb+|b)b - abb abb b
a(bbb+|bb+|b)b - abbb abbb bb
a(bbb+|bb+|b)bb - abbb abbb b
(.*).* - abcdef abcdef abcdef
(a*)* - bc @b @b
# do we get the right subexpression when it is used more than once?
a(b|c)*d - ad ad -
a(b|c)*d - abcd abcd c
a(b|c)+d - abd abd b
a(b|c)+d - abcd abcd c
a(b|c?)+d - ad ad @d
a(b|c?)+d - abcd abcd @d
a(b|c){0,0}d - ad ad -
a(b|c){0,1}d - ad ad -
a(b|c){0,1}d - abd abd b
a(b|c){0,2}d - ad ad -
a(b|c){0,2}d - abcd abcd c
a(b|c){0,}d - ad ad -
a(b|c){0,}d - abcd abcd c
a(b|c){1,1}d - abd abd b
a(b|c){1,1}d - acd acd c
a(b|c){1,2}d - abd abd b
a(b|c){1,2}d - abcd abcd c
a(b|c){1,}d - abd abd b
a(b|c){1,}d - abcd abcd c
a(b|c){2,2}d - acbd acbd b
a(b|c){2,2}d - abcd abcd c
a(b|c){2,4}d - abcd abcd c
a(b|c){2,4}d - abcbd abcbd b
a(b|c){2,4}d - abcbcd abcbcd c
a(b|c){2,}d - abcd abcd c
a(b|c){2,}d - abcbd abcbd b
a(b+|((c)*))+d - abd abd @d,@d,-
a(b+|((c)*))+d - abcd abcd @d,@d,-
# check out the STARTEND option
[abc] &# a(b)c b
[abc] &# a(d)c
[abc] &# a(bc)d b
[abc] &# a(dc)d c
. &# a()c
b.*c &# b(bc)c bc
b.* &# b(bc)c bc
.*c &# b(bc)c bc
# plain strings, with the NOSPEC flag
abc m abc abc
abc m xabcy abc
abc m xyz
a*b m aba*b a*b
a*b m ab
"" mC EMPTY
# cases involving NULs
aZb & a a
aZb &p a
aZb &p# (aZb) aZb
aZ*b &p# (ab) ab
a.b &# (aZb) aZb
a.* &# (aZb)c aZb
# word boundaries (ick)
[[:<:]]a & a a
[[:<:]]a & ba
[[:<:]]a & -a a
a[[:>:]] & a a
a[[:>:]] & ab
a[[:>:]] & a- a
[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc abc
[[:<:]]a.c[[:>:]] & axcd-dayc-dazce-abc-q abc
[[:<:]]a.c[[:>:]] & axc-dayc-dazce-abc axc
[[:<:]]b.c[[:>:]] & a_bxc-byc_d-bzc-q bzc
[[:<:]].x..[[:>:]] & y_xa_-_xb_y-_xc_-axdc _xc_
[[:<:]]a_b[[:>:]] & x_a_b
# past problems, and suspected problems
(A[1])|(A[2])|(A[3])|(A[4])|(A[5])|(A[6])|(A[7])|(A[8])|(A[9])|(A[A]) - A1 A1
abcdefghijklmnop i abcdefghijklmnop abcdefghijklmnop
abcdefghijklmnopqrstuv i abcdefghijklmnopqrstuv abcdefghijklmnopqrstuv
(ALAK)|(ALT[AB])|(CC[123]1)|(CM[123]1)|(GAMC)|(LC[23][EO ])|(SEM[1234])|(SL[ES][12])|(SLWW)|(SLF )|(SLDT)|(VWH[12])|(WH[34][EW])|(WP1[ESN]) - CC11 CC11
CC[13]1|a{21}[23][EO][123][Es][12]a{15}aa[34][EW]aaaaaaa[X]a - CC11 CC11
Char \([a-z0-9_]*\)\[.* b Char xyz[k Char xyz[k xyz
a?b - ab ab
-\{0,1\}[0-9]*$ b -5 -5
a*a*a*a*a*a*a* & aaaaaa aaaaaa

File diff suppressed because it is too large Load Diff

View File

@ -1219,7 +1219,7 @@ TEST_F(TestBatchExecute, partial_update)
// create table if not exists append_lob_test (C1 bigint primary key, C2 bigint, C3 mediumtext not null);
TEST_F(TestBatchExecute, append_lob)
/*TEST_F(TestBatchExecute, append_lob)
{
// setup
ObTable *the_table = NULL;
@ -1340,7 +1340,7 @@ TEST_F(TestBatchExecute, append_lob)
service_client_->free_table(the_table);
the_table = NULL;
}
*/
// for lob column
// drop table if exists all_lob_test; create table if not exists all_lob_test (C1 bigint primary key, C2 bigint, C3 mediumtext, index i1(c2) local)
// TEST_F(TestBatchExecute, lob_column_test)
@ -1557,7 +1557,7 @@ TEST_F(TestBatchExecute, append_lob)
// create table if not exists virtual_generate_col_test
// (C1 bigint primary key, C2 bigint, C3 varchar(100),
// C3_PREFIX varchar(10) GENERATED ALWAYS AS (substr(C3,1,2)));
TEST_F(TestBatchExecute, virtual_generate_col_test)
/*TEST_F(TestBatchExecute, virtual_generate_col_test)
{
// setup
ObTable *the_table = NULL;
@ -1664,7 +1664,6 @@ TEST_F(TestBatchExecute, virtual_generate_col_test)
service_client_->free_table(the_table);
the_table = NULL;
}
// create table if not exists store_generate_col_test
// (c1 bigint primary key, c2 varchar(10), c3 varchar(10),
// gen varchar(30) generated always as (concat(c2,c3)) stored)
@ -1849,7 +1848,7 @@ TEST_F(TestBatchExecute, stored_generate_col_test)
service_client_->free_table(the_table);
the_table = NULL;
}
*/
// create table if not exists large_scan_test (C1 bigint primary key, C2 bigint, C3 varchar(100));
TEST_F(TestBatchExecute, large_scan)
{
@ -6053,7 +6052,7 @@ TEST_F(TestBatchExecute, htable_scan_with_filter)
delete [] rows;
}
TEST_F(TestBatchExecute, single_increment_append)
/*TEST_F(TestBatchExecute, single_increment_append)
{
OB_LOG(INFO, "begin single_increment");
ObTable *the_table = NULL;
@ -6380,7 +6379,7 @@ TEST_F(TestBatchExecute, single_increment_append)
}
service_client_->free_table(the_table);
}
*/
// create table if not exists multi_update_test
// (C1 bigint primary key, C2 double, C3 varchar(100) default 'hello world')
// PARTITION BY KEY(C1) PARTITIONS 16
@ -7595,7 +7594,7 @@ TEST_F(TestBatchExecute, complex_batch_execute)
}
service_client_->free_table(the_table);
}
/*
TEST_F(TestBatchExecute, increment_and_append_batch)
{
ObTable *the_table = NULL;
@ -7737,7 +7736,7 @@ TEST_F(TestBatchExecute, increment_and_append_batch)
}
}
}
*/
TEST_F(TestBatchExecute, htable_put)
{
// setup

View File

@ -2226,6 +2226,7 @@ typedef enum ObContextType {
|| ((op) == T_FUN_SYS_JSON_EXISTS) \
|| ((op) == T_BOOL) \
|| ((op) == T_OP_XOR) \
|| ((op) == T_FUN_SYS_IS_UUID) \
|| ((op) == T_FUN_SYS_ST_CONTAINS) \
|| ((op) == T_FUN_SYS_ST_WITHIN) \
|| ((op) == T_FUN_SYS_ST_DWITHIN) \
@ -2342,6 +2343,12 @@ inline ObItemType get_opposite_compare_type(ObItemType src_type)
case T_OP_GE:
ret_type = T_OP_LE;
break;
case T_OP_EXISTS:
ret_type = T_OP_NOT_EXISTS;
break;
case T_OP_NOT_EXISTS:
ret_type = T_OP_EXISTS;
break;
default:
ret_type = src_type;
break;

View File

@ -117,6 +117,10 @@ public:
inline bool is_calc_part_expr() const { return T_FUN_SYS_CALC_PARTITION_ID == type_
|| T_FUN_SYS_CALC_TABLET_ID == type_
|| T_FUN_SYS_CALC_PARTITION_TABLET_ID == type_; }
inline bool is_basic_const_expr_mysql() const { return EXPR_CONST == expr_class_
|| T_FUN_SYS_VERSION == type_
|| T_FUN_SYS_OB_VERSION == type_
|| T_FUN_SYS_ICU_VERSION == type_; }
inline void set_expr_type(ObItemType v) { type_ = v; }
inline ObItemType get_expr_type() const { return type_; }

View File

@ -310,8 +310,12 @@ ob_set_subtarget(ob_server virtual_table
virtual_table/ob_virtual_ash.cpp
virtual_table/ob_virtual_sql_plan_statistics.cpp
virtual_table/ob_virtual_table_iterator_factory.cpp
virtual_table/ob_virtual_trace_log.cpp
virtual_table/ob_all_virtual_dml_stats.cpp
virtual_table/ob_virtual_span_info.cpp
virtual_table/ob_virtual_show_trace.cpp
virtual_table/ob_all_virtual_sql_plan.cpp
virtual_table/ob_all_virtual_plan_table.cpp
virtual_table/ob_all_virtual_plan_real_info.cpp
)
ob_server_add_target(ob_server)

View File

@ -234,13 +234,12 @@ int ObMySQLRequestManager::get_mem_limit(uint64_t tenant_id,
ObArenaAllocator alloc;
ObObj obj_val;
int64_t mem_pct = 0;
const char* conf_name = "ob_sql_audit_percentage";
if (OB_FAIL(ObBasicSessionInfo::get_global_sys_variable(tenant_id,
alloc,
ObDataTypeCastParams(),
ObString(conf_name),
ObString(OB_SV_SQL_AUDIT_PERCENTAGE),
obj_val))) {
LOG_WARN("failed to get global sys variable", K(ret), K(tenant_id), K(conf_name), K(obj_val));
LOG_WARN("failed to get global sys variable", K(ret), K(tenant_id), K(OB_SV_SQL_AUDIT_PERCENTAGE), K(obj_val));
} else if (OB_FAIL(obj_val.get_int(mem_pct))) {
LOG_WARN("failed to get int", K(ret), K(obj_val));
} else if (mem_pct < 0 || mem_pct > 100) {

View File

@ -48,6 +48,18 @@ int ObSyncCmdDriver::send_eof_packet(bool has_more_result)
{
int ret = OB_SUCCESS;
OMPKEOF eofp;
if (OB_FAIL(seal_eof_packet(has_more_result, eofp))) {
LOG_WARN("failed to seal eof packet", K(ret), K(has_more_result));
} else if (OB_FAIL(sender_.response_packet(eofp, &session_))) {
LOG_WARN("response packet fail", K(ret), K(has_more_result));
}
return ret;
}
int ObSyncCmdDriver::seal_eof_packet(bool has_more_result, OMPKEOF& eofp)
{
int ret = OB_SUCCESS;
const ObWarningBuffer *warnings_buf = common::ob_get_tsi_warning_buffer();
uint16_t warning_count = 0;
if (OB_ISNULL(warnings_buf)) {
@ -75,12 +87,6 @@ int ObSyncCmdDriver::send_eof_packet(bool has_more_result)
&& OB_FAIL(sender_.update_last_pkt_pos())) {
LOG_WARN("failed to update last packet pos", K(ret));
}
if (OB_FAIL(ret)) {
// do nothing
} else if (OB_FAIL(sender_.response_packet(eofp, &session_))) {
LOG_WARN("response packet fail", K(ret), K(has_more_result));
}
return ret;
}
@ -100,6 +106,8 @@ int ObSyncCmdDriver::response_result(ObMySQLResultSet &result)
int ret = OB_SUCCESS;
bool process_ok = false;
// for select SQL
OMPKEOF eofp;
bool need_send_eof = false;
if (OB_FAIL(result.open())) {
// 只有open失败的时候才可能重试,因open的时候会开启事务/语句等,并且没有给用户返回任何信息
int cret = OB_SUCCESS;
@ -133,8 +141,10 @@ int ObSyncCmdDriver::response_result(ObMySQLResultSet &result)
LOG_WARN("close result set fail", K(cret));
}
} else {
if (OB_FAIL(send_eof_packet(result.has_more_result()))) {
if (OB_FAIL(seal_eof_packet(result.has_more_result(), eofp))) {
LOG_WARN("failed to send eof package", K(ret), K(result.has_more_result()));
} else {
need_send_eof = true;
}
}
} else { /*do nothing*/ }
@ -164,10 +174,20 @@ int ObSyncCmdDriver::response_result(ObMySQLResultSet &result)
ok_param.is_partition_hit_ = session_.partition_hit().get_bool();
ok_param.has_more_result_ = result.has_more_result();
ok_param.has_pl_out_ = is_prexecute_ && result.is_with_rows() ? true : false;
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param))) {
LOG_WARN("send ok packet fail", K(ok_param), K(ret));
if (need_send_eof) {
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param, &eofp))) {
LOG_WARN("send ok packet fail", K(ok_param), K(ret));
}
} else {
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param))) {
LOG_WARN("send ok packet fail", K(ok_param), K(ret));
}
}
} else { /*do nothing*/ }
} else {
if (need_send_eof && OB_FAIL(sender_.response_packet(eofp, &session_))) {
LOG_WARN("response packet fail", K(ret));
}
}
}
if (!OB_SUCC(ret) && !process_ok && !retry_ctrl_.need_retry()) {

View File

@ -14,6 +14,7 @@
#define OCEANBASE_OBSERVER_MYSQL_SYNC_CMD_DRIVER_
#include "observer/mysql/ob_query_driver.h"
#include "rpc/obmysql/packet/ompk_eof.h"
namespace oceanbase
{
@ -44,6 +45,7 @@ public:
virtual ~ObSyncCmdDriver();
int send_eof_packet(bool has_more_result);
int seal_eof_packet(bool has_more_result, obmysql::OMPKEOF& eofp);
virtual int response_query_result(sql::ObResultSet &result,
bool is_ps_protocol,
bool has_more_result,

View File

@ -126,6 +126,7 @@ int ObSyncPlanDriver::response_result(ObMySQLResultSet &result)
process_ok = true;
OMPKEOF eofp;
bool need_send_eof = false;
const ObWarningBuffer *warnings_buf = common::ob_get_tsi_warning_buffer();
uint16_t warning_count = 0;
if (OB_ISNULL(warnings_buf)) {
@ -154,9 +155,8 @@ int ObSyncPlanDriver::response_result(ObMySQLResultSet &result)
&& OB_FAIL(sender_.update_last_pkt_pos())) {
LOG_WARN("failed to update last packet pos", K(ret));
}
if (OB_SUCC(ret) && !result.get_is_com_filed_list() &&
OB_FAIL(sender_.response_packet(eofp, &result.get_session()))) {
LOG_WARN("response packet fail", K(ret));
if (OB_SUCC(ret) && !result.get_is_com_filed_list()) {
need_send_eof = true;
}
// for obproxy
if (OB_SUCC(ret)) {
@ -167,8 +167,18 @@ int ObSyncPlanDriver::response_result(ObMySQLResultSet &result)
ok_param.affected_rows_ = 0;
ok_param.is_partition_hit_ = session_.partition_hit().get_bool();
ok_param.has_more_result_ = result.has_more_result();
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param))) {
LOG_WARN("fail to send ok packt", K(ok_param), K(ret));
if (need_send_eof) {
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param, &eofp))) {
LOG_WARN("fail to send ok packt", K(ok_param), K(ret));
}
} else {
if (OB_FAIL(sender_.send_ok_packet(session_, ok_param))) {
LOG_WARN("fail to send ok packt", K(ok_param), K(ret));
}
}
} else {
if (need_send_eof && OB_FAIL(sender_.response_packet(eofp, &result.get_session()))) {
LOG_WARN("response packet fail", K(ret));
}
}
}

Some files were not shown because too many files have changed in this diff Show More