mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-31 09:23:03 +01:00
493 lines
11 KiB
C++
493 lines
11 KiB
C++
|
/*
|
||
|
* PROGRAM: JRD Data Definition Language
|
||
|
* MODULE: hsh.c
|
||
|
* DESCRIPTION: Hash table and symbol manager
|
||
|
*
|
||
|
* The contents of this file are subject to the Interbase Public
|
||
|
* License Version 1.0 (the "License"); you may not use this file
|
||
|
* except in compliance with the License. You may obtain a copy
|
||
|
* of the License at http://www.Inprise.com/IPL.html
|
||
|
*
|
||
|
* Software distributed under the License is distributed on an
|
||
|
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
||
|
* or implied. See the License for the specific language governing
|
||
|
* rights and limitations under the License.
|
||
|
*
|
||
|
* The Original Code was created by Inprise Corporation
|
||
|
* and its predecessors. Portions created by Inprise Corporation are
|
||
|
* Copyright (C) Inprise Corporation.
|
||
|
*
|
||
|
* All Rights Reserved.
|
||
|
* Contributor(s): ______________________________________.
|
||
|
*/
|
||
|
|
||
|
#include "../dudley/ddl.h"
|
||
|
#include "../dudley/parse.h"
|
||
|
|
||
|
#if (defined JPN_SJIS || defined JPN_EUC)
|
||
|
#include "../jrd/kanji.h"
|
||
|
#endif
|
||
|
#include "../dudley/ddl_proto.h"
|
||
|
#include "../dudley/hsh_proto.h"
|
||
|
|
||
|
|
||
|
extern "C" {
|
||
|
|
||
|
|
||
|
#define HASH_SIZE 101
|
||
|
|
||
|
static USHORT hash(register SCHAR *, register USHORT);
|
||
|
static BOOLEAN scompare(register SCHAR *, register USHORT, register SCHAR *,
|
||
|
USHORT);
|
||
|
|
||
|
static SYM hash_table[HASH_SIZE];
|
||
|
static SYM key_symbols;
|
||
|
|
||
|
struct word {
|
||
|
enum kwwords id;
|
||
|
SCHAR *keyword;
|
||
|
} keywords[] = {
|
||
|
KW_OR, "||",
|
||
|
KW_AND, "&&",
|
||
|
KW_GE, ">=",
|
||
|
KW_LE, "<=",
|
||
|
KW_NE, "<>",
|
||
|
KW_NE, "!=",
|
||
|
KW_NE, "~=",
|
||
|
KW_EQ, "==",
|
||
|
KW_GT, ">",
|
||
|
KW_LT, "<",
|
||
|
KW_PERCENT, "%",
|
||
|
KW_EQUALS, "=",
|
||
|
KW_COMMA, ",",
|
||
|
KW_DOT, ".",
|
||
|
KW_L_BRCKET, "[",
|
||
|
KW_LEFT_PAREN, "(",
|
||
|
KW_MINUS, "-",
|
||
|
KW_R_BRCKET, "]",
|
||
|
KW_RIGHT_PAREN, ")",
|
||
|
KW_PLUS, "+",
|
||
|
KW_SEMI, ";",
|
||
|
KW_SLASH, "/",
|
||
|
KW_ASTERISK, "*",
|
||
|
KW_BAR, "|",
|
||
|
KW_COLON, ":",
|
||
|
KW_ABORT, "ABORT",
|
||
|
KW_ACL, "ACL",
|
||
|
KW_ACTIVE, "ACTIVE",
|
||
|
KW_ADD, "ADD",
|
||
|
KW_ALL, "ALL",
|
||
|
KW_ARRAY, "ARRAY",
|
||
|
KW_AT, "AT",
|
||
|
KW_AUTO, "AUTO",
|
||
|
KW_BASED, "BASED",
|
||
|
KW_BASE_NAME, "BASE_NAME",
|
||
|
KW_BEGIN, "BEGIN",
|
||
|
KW_BLOB, "BLOB",
|
||
|
KW_BLR, "BLR",
|
||
|
KW_CACHE, "CACHE",
|
||
|
KW_CASCADE, "CASCADE",
|
||
|
KW_CHAR, "CHAR",
|
||
|
KW_CHECK_POINT_LEN, "CHECK_POINT_LENGTH",
|
||
|
KW_COMPUTED, "COMPUTED_BY",
|
||
|
KW_COMPUTED, "COMPUTED",
|
||
|
KW_CONDITIONAL, "CONDITIONAL",
|
||
|
KW_CONSTRAINT, "CONSTRAINT",
|
||
|
KW_CSTRING, "CSTRING",
|
||
|
KW_DATABASE, "DATABASE",
|
||
|
KW_DATE, "DATE",
|
||
|
KW_DEFINE, "DEFINE",
|
||
|
KW_DEFAULT, "DEFAULT",
|
||
|
KW_DELETE, "DELETE",
|
||
|
KW_DESCRIP, "DESCRIPTION",
|
||
|
KW_DESCRIPTION, "{",
|
||
|
KW_DOUBLE, "DOUBLE",
|
||
|
KW_DROP, "DROP",
|
||
|
KW_DROP, "DELETE",
|
||
|
KW_DUPLICATES, "DUPLICATE",
|
||
|
KW_DUPLICATES, "DUPLICATES",
|
||
|
KW_EDIT_STRING, "EDIT_STRING",
|
||
|
KW_ELSE, "ELSE",
|
||
|
KW_END, "END",
|
||
|
KW_END_DESCRIPTION, "}",
|
||
|
KW_END_FOR, "END_FOR",
|
||
|
KW_END_MODIFY, "END_MODIFY",
|
||
|
KW_END_STORE, "END_STORE",
|
||
|
KW_END_TRIGGER, "END_TRIGGER",
|
||
|
KW_ERASE, "ERASE",
|
||
|
KW_EXIT, "EXIT",
|
||
|
KW_EXTERNAL_FILE, "EXTERNAL_FILE",
|
||
|
KW_FIELD, "FIELD",
|
||
|
KW_FILE, "FILE",
|
||
|
KW_FILTER, "FILTER",
|
||
|
KW_FIXED, "FIXED",
|
||
|
KW_FLOAT, "FLOAT",
|
||
|
KW_FOR, "FOR",
|
||
|
KW_FUNCTION, "FUNCTION",
|
||
|
KW_FUNCTION_ENTRY_POINT, "ENTRY_POINT",
|
||
|
KW_FUNCTION_MODULE_NAME, "MODULE_NAME",
|
||
|
KW_GENERATOR, "GENERATOR",
|
||
|
KW_GRANT, "GRANT",
|
||
|
KW_GROUP, "GROUP",
|
||
|
KW_GROUP_COMMIT_WAIT, "GROUP_COMMIT_WAIT_TIME",
|
||
|
KW_IF, "IF",
|
||
|
KW_INACTIVE, "INACTIVE",
|
||
|
KW_INDEX, "INDEX",
|
||
|
KW_INPUT_TYPE, "INPUT_TYPE",
|
||
|
KW_INSERT, "INSERT",
|
||
|
KW_IS, "IS",
|
||
|
KW_LENGTH, "LENGTH",
|
||
|
KW_LOG_BUF_SIZE, "LOG_BUFFER_SIZE",
|
||
|
KW_LOG_FILE, "LOGFILE",
|
||
|
KW_LONG, "LONG",
|
||
|
KW_MANUAL, "MANUAL",
|
||
|
KW_MESSAGE, "MESSAGE",
|
||
|
KW_MISSING, "MISSING_VALUE",
|
||
|
KW_MISSING, "MISSING",
|
||
|
KW_MODIFY, "MODIFY",
|
||
|
KW_MSGADD, "MSGADD",
|
||
|
KW_MSGDROP, "MSGDROP",
|
||
|
KW_MSGMODIFY, "MSGMODIFY",
|
||
|
KW_NULL, "NULL",
|
||
|
KW_NUM_LOG_BUFS, "NUM_LOG_BUFFERS",
|
||
|
KW_OFFSET, "OFFSET",
|
||
|
KW_ON, "ON",
|
||
|
KW_OPTION, "OPTION",
|
||
|
KW_OUTPUT_TYPE, "OUTPUT_TYPE",
|
||
|
KW_OVERFLOW, "OVERFLOW",
|
||
|
KW_OVERWRITE, "OVERWRITE",
|
||
|
KW_PAGE, "PAGE",
|
||
|
KW_PAGES, "PAGES",
|
||
|
KW_PAGE_NUMBER, "PAGE_NUMBER",
|
||
|
KW_PAGE_SIZE, "PAGE_SIZE",
|
||
|
KW_PARTITIONS, "PARTITIONS",
|
||
|
KW_PASSWORD, "PASSWORD",
|
||
|
KW_POSITION, "POSITION",
|
||
|
KW_POST, "POST",
|
||
|
KW_POST_ERASE, "POST_ERASE",
|
||
|
KW_POST_MODIFY, "POST_MODIFY",
|
||
|
KW_POST_STORE, "POST_STORE",
|
||
|
KW_PRE, "PRE",
|
||
|
KW_PRE_ALLOCATE, "PRE_ALLOCATE",
|
||
|
KW_PRE_ERASE, "PRE_ERASE",
|
||
|
KW_PRE_MODIFY, "PRE_MODIFY",
|
||
|
KW_PRE_STORE, "PRE_STORE",
|
||
|
KW_PRIVILEGES, "PRIVILEGES",
|
||
|
KW_QUAD, "QUAD",
|
||
|
KW_QUERY_NAME, "QUERY_NAME",
|
||
|
KW_QUERY_HEADER, "QUERY_HEADER",
|
||
|
KW_RAW, "RAW",
|
||
|
KW_RAW_PARTITIONS, "RAW_PARTITIONS",
|
||
|
KW_REFERENCE, "REFERENCE",
|
||
|
KW_RELATION, "RELATION", KW_RETURN_ARGUMENT, "RETURN_ARGUMENT", /* function argument return_mode */
|
||
|
KW_RETURN_VALUE, "RETURN_VALUE", /* function argument return_mode */
|
||
|
KW_REVOKE, "REVOKE",
|
||
|
KW_SCALAR_ARRAY_DESCRIPTOR, "SCALAR_ARRAY_DESCRIPTOR",
|
||
|
KW_SCALE, "SCALE",
|
||
|
KW_SELECT, "SELECT",
|
||
|
KW_SECURITY_CLASS, "SECURITY_CLASS",
|
||
|
KW_SEGMENT_LENGTH, "SEGMENT_LENGTH",
|
||
|
KW_SET, "SET",
|
||
|
KW_SET_GENERATOR, "SET_GENERATOR",
|
||
|
KW_SHADOW, "SHADOW",
|
||
|
KW_SHORT, "SHORT",
|
||
|
KW_SIZE, "SIZE",
|
||
|
KW_SORTED, "SORTED",
|
||
|
KW_STATISTICS, "STATISTICS",
|
||
|
KW_STORE, "STORE",
|
||
|
KW_SUB_TYPE, "SUB_TYPE",
|
||
|
KW_SYSTEM_FLAG, "SYSTEM_FLAG",
|
||
|
KW_TEXT, "TEXT",
|
||
|
KW_THEN, "THEN",
|
||
|
KW_TO, "TO",
|
||
|
KW_TRIGGER, "TRIGGER",
|
||
|
KW_TYPES, "TYPES",
|
||
|
KW_UPDATE, "UPDATE",
|
||
|
KW_USER, "USER",
|
||
|
KW_USER_NAME, "RDB$USER_NAME",
|
||
|
KW_USING, "USING",
|
||
|
KW_VALID_IF, "VALID_IF",
|
||
|
KW_VALID_IF, "VALID",
|
||
|
KW_VALUE, "VALUE",
|
||
|
KW_VARYING, "VARYING",
|
||
|
KW_VIEW, "VIEW",
|
||
|
KW_AND, "AND",
|
||
|
KW_ANY, "ANY",
|
||
|
KW_ASCENDING, "ASC",
|
||
|
KW_ASCENDING, "ASCENDING",
|
||
|
KW_ASTERISK, "ASTERISK",
|
||
|
KW_AVERAGE, "AVERAGE",
|
||
|
KW_BETWEEN, "BETWEEN",
|
||
|
KW_BY, "BY",
|
||
|
KW_CONTAINING, "CONTAINING",
|
||
|
KW_COUNT, "COUNT",
|
||
|
KW_CROSS, "CROSS",
|
||
|
KW_DESCENDING, "DESC",
|
||
|
KW_DESCENDING, "DESCENDING",
|
||
|
KW_ELSE, "ELSE",
|
||
|
KW_EQ, "EQ",
|
||
|
KW_FIRST, "FIRST",
|
||
|
KW_FROM, "FROM",
|
||
|
KW_GEN_ID, "GEN_ID",
|
||
|
KW_GE, "GE",
|
||
|
KW_GT, "GT",
|
||
|
KW_IN, "IN",
|
||
|
KW_LE, "LE",
|
||
|
KW_LT, "LT",
|
||
|
KW_MATCHES, "MATCHES",
|
||
|
KW_MATCHES, "MATCHING",
|
||
|
KW_MIN, "MIN",
|
||
|
KW_MINUS, "MINUS",
|
||
|
KW_MISSING, "MISSING",
|
||
|
KW_NE, "NE",
|
||
|
KW_NOT, "NOT",
|
||
|
KW_OF, "OF",
|
||
|
KW_OR, "OR",
|
||
|
KW_OVER, "OVER",
|
||
|
KW_QUIT, "QUIT",
|
||
|
KW_REDUCED, "REDUCED",
|
||
|
KW_SLASH, "SLASH",
|
||
|
KW_SORTED, "SORTED",
|
||
|
KW_STARTS, "STARTS",
|
||
|
KW_STARTS, "STARTING",
|
||
|
KW_STARTS, "STARTS_WITH",
|
||
|
KW_STARTS, "STARTING_WITH",
|
||
|
KW_MAX, "MAX",
|
||
|
KW_TO, "TO",
|
||
|
KW_TOTAL, "TOTAL",
|
||
|
KW_UNIQUE, "UNIQUE", KW_UPPERCASE, "UPPERCASE", KW_WITH, "WITH"};
|
||
|
|
||
|
#define NUMWORDS (sizeof (keywords) / sizeof (struct word))
|
||
|
|
||
|
|
||
|
void HSH_init(void)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* H S H _ i n i t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Initialize the hash table. This mostly involves
|
||
|
* inserting all known keywords.
|
||
|
*
|
||
|
**************************************/
|
||
|
register SCHAR *string;
|
||
|
register SYM symbol;
|
||
|
register SSHORT i, length;
|
||
|
|
||
|
for (i = 0; i < NUMWORDS; i++) {
|
||
|
string = keywords[i].keyword;
|
||
|
for (length = 0; string[length] != '\0'; length++);
|
||
|
symbol = (SYM) DDL_alloc(SYM_LEN);
|
||
|
symbol->sym_type = SYM_keyword;
|
||
|
symbol->sym_length = length;
|
||
|
symbol->sym_string = keywords[i].keyword;
|
||
|
symbol->sym_keyword = (int) keywords[i].id;
|
||
|
HSH_insert(symbol);
|
||
|
symbol->sym_object = (CTX) key_symbols;
|
||
|
key_symbols = symbol;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
void HSH_insert( register SYM symbol)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* H S H _ i n s e r t
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Insert a symbol into the hash table.
|
||
|
*
|
||
|
**************************************/
|
||
|
register USHORT h;
|
||
|
register SYM old;
|
||
|
|
||
|
h = hash(symbol->sym_string, symbol->sym_length);
|
||
|
|
||
|
for (old = hash_table[h]; old; old = old->sym_collision)
|
||
|
if (scompare(symbol->sym_string, symbol->sym_length,
|
||
|
old->sym_string, old->sym_length)) {
|
||
|
symbol->sym_homonym = old->sym_homonym;
|
||
|
old->sym_homonym = symbol;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
symbol->sym_collision = hash_table[h];
|
||
|
hash_table[h] = symbol;
|
||
|
}
|
||
|
|
||
|
|
||
|
SYM HSH_lookup(register SCHAR * string, register USHORT length)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* H S H _ l o o k u p
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Perform a string lookup against hash table.
|
||
|
*
|
||
|
**************************************/
|
||
|
register SYM symbol;
|
||
|
|
||
|
for (symbol = hash_table[hash(string, length)]; symbol;
|
||
|
symbol = symbol->sym_collision)
|
||
|
if (scompare
|
||
|
(string, length, symbol->sym_string,
|
||
|
symbol->sym_length)) return symbol;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
void HSH_remove( register SYM symbol)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* H S H _ r e m o v e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Remove a symbol from the hash table.
|
||
|
*
|
||
|
**************************************/
|
||
|
USHORT h;
|
||
|
register SYM *next, *ptr, homonym;
|
||
|
|
||
|
h = hash(symbol->sym_string, symbol->sym_length);
|
||
|
|
||
|
for (next = &hash_table[h]; *next; next = &(*next)->sym_collision)
|
||
|
if (symbol == *next)
|
||
|
if (homonym = symbol->sym_homonym) {
|
||
|
homonym->sym_collision = symbol->sym_collision;
|
||
|
*next = homonym;
|
||
|
return;
|
||
|
}
|
||
|
else {
|
||
|
*next = symbol->sym_collision;
|
||
|
return;
|
||
|
}
|
||
|
else
|
||
|
for (ptr = &(*next)->sym_homonym; *ptr;
|
||
|
ptr = &(*ptr)->sym_homonym) if (symbol == *ptr) {
|
||
|
*ptr = symbol->sym_homonym;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
DDL_err(280, NULL, NULL, NULL, NULL, NULL); /* msg 280: HSH_remove failed */
|
||
|
}
|
||
|
|
||
|
|
||
|
SYM HSH_typed_lookup(register TEXT * string,
|
||
|
register USHORT length, enum sym_t type)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* H S H _ t y p e d _ l o o k u p
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Perform a string lookup against hash table
|
||
|
* considering the object type. If length is
|
||
|
* 0, assume that the string is terminated by
|
||
|
* a null or space and compute the length.
|
||
|
*
|
||
|
**************************************/
|
||
|
register SYM symbol;
|
||
|
TEXT *p;
|
||
|
|
||
|
if (!length) {
|
||
|
for (p = string; *p && *p != ' '; p++)
|
||
|
if ((p - string) >= 32)
|
||
|
break;
|
||
|
length = p - string;
|
||
|
}
|
||
|
|
||
|
symbol = HSH_lookup(string, length);
|
||
|
|
||
|
for (; symbol; symbol = symbol->sym_homonym)
|
||
|
if (symbol->sym_type == type)
|
||
|
break;
|
||
|
|
||
|
return symbol;
|
||
|
}
|
||
|
|
||
|
|
||
|
static USHORT hash( register SCHAR * string, register USHORT length)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* h a s h
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Returns the hash function of a string.
|
||
|
*
|
||
|
**************************************/
|
||
|
register USHORT value;
|
||
|
SCHAR c;
|
||
|
|
||
|
value = 0;
|
||
|
|
||
|
while (length--) {
|
||
|
c = *string++;
|
||
|
value = (value << 1) + UPPER(c);
|
||
|
}
|
||
|
|
||
|
return value % HASH_SIZE;
|
||
|
}
|
||
|
|
||
|
|
||
|
static BOOLEAN scompare(
|
||
|
register SCHAR * string1,
|
||
|
register USHORT length1,
|
||
|
register SCHAR * string2, USHORT length2)
|
||
|
{
|
||
|
/**************************************
|
||
|
*
|
||
|
* s c o m p a r e
|
||
|
*
|
||
|
**************************************
|
||
|
*
|
||
|
* Functional description
|
||
|
* Compare two strings
|
||
|
*
|
||
|
**************************************/
|
||
|
SCHAR c1, c2;
|
||
|
|
||
|
if (length1 != length2)
|
||
|
return FALSE;
|
||
|
|
||
|
while (length1--)
|
||
|
#ifdef JPN_SJIS
|
||
|
{
|
||
|
#endif
|
||
|
if ((c1 = *string1++) != (c2 = *string2++) && UPPER(c1) != UPPER(c2))
|
||
|
return FALSE;
|
||
|
#ifdef JPN_SJIS
|
||
|
|
||
|
/* Do not upcase second byte of a sjis kanji character */
|
||
|
|
||
|
if (KANJI1(c1) && length1 > 1) {
|
||
|
if ((c1 = *string1++) != (c2 = *string2++))
|
||
|
return FALSE;
|
||
|
length1--;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
} // extern "C"
|