mirror of
https://github.com/FirebirdSQL/firebird.git
synced 2025-01-24 06:03:02 +01:00
469 lines
11 KiB
C++
469 lines
11 KiB
C++
/*
|
|
* PROGRAM: JRD Data Definition Language
|
|
* MODULE: hsh.cpp
|
|
* 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 "firebird.h"
|
|
#include "../dudley/ddl.h"
|
|
#include "../dudley/parse.h"
|
|
|
|
#include "../dudley/ddl_proto.h"
|
|
#include "../dudley/hsh_proto.h"
|
|
|
|
|
|
const int HASH_SIZE = 101;
|
|
|
|
static USHORT hash(const SCHAR*, USHORT);
|
|
static bool scompare(const SCHAR*, USHORT, const SCHAR*, const USHORT);
|
|
|
|
static SYM hash_table[HASH_SIZE];
|
|
static SYM key_symbols;
|
|
|
|
struct word {
|
|
enum kwwords id;
|
|
const char* 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"}
|
|
};
|
|
|
|
|
|
void HSH_init(void)
|
|
{
|
|
/**************************************
|
|
*
|
|
* H S H _ i n i t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Initialize the hash table. This mostly involves
|
|
* inserting all known keywords.
|
|
*
|
|
**************************************/
|
|
SYM symbol;
|
|
int i;
|
|
SSHORT length;
|
|
|
|
for (i = 0; i < FB_NELEM(keywords); i++) {
|
|
const char* 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 = (DUDLEY_CTX) key_symbols;
|
|
key_symbols = symbol;
|
|
}
|
|
}
|
|
|
|
|
|
void HSH_insert( SYM symbol)
|
|
{
|
|
/**************************************
|
|
*
|
|
* H S H _ i n s e r t
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Insert a symbol into the hash table.
|
|
*
|
|
**************************************/
|
|
USHORT h;
|
|
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(const SCHAR* string, USHORT length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* H S H _ l o o k u p
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Perform a string lookup against hash table.
|
|
*
|
|
**************************************/
|
|
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( SYM symbol)
|
|
{
|
|
/**************************************
|
|
*
|
|
* H S H _ r e m o v e
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Remove a symbol from the hash table.
|
|
*
|
|
**************************************/
|
|
USHORT h;
|
|
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(const TEXT* string,
|
|
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.
|
|
*
|
|
**************************************/
|
|
if (!length) {
|
|
const TEXT* p;
|
|
for (p = string; *p && *p != ' '; p++)
|
|
if ((p - string) >= 32)
|
|
break;
|
|
length = p - string;
|
|
}
|
|
|
|
SYM symbol = HSH_lookup(string, length);
|
|
|
|
for (; symbol; symbol = symbol->sym_homonym)
|
|
if (symbol->sym_type == type)
|
|
break;
|
|
|
|
return symbol;
|
|
}
|
|
|
|
|
|
static USHORT hash(const SCHAR* string, USHORT length)
|
|
{
|
|
/**************************************
|
|
*
|
|
* h a s h
|
|
*
|
|
**************************************
|
|
*
|
|
* Functional description
|
|
* Returns the hash function of a string.
|
|
*
|
|
**************************************/
|
|
USHORT value = 0;
|
|
|
|
while (length--) {
|
|
const SCHAR c = *string++;
|
|
value = (value << 1) + UPPER(c);
|
|
}
|
|
|
|
return value % HASH_SIZE;
|
|
}
|
|
|
|
|
|
static bool scompare(const SCHAR* string1,
|
|
USHORT length1,
|
|
const SCHAR* string2,
|
|
const 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--)
|
|
if ((c1 = *string1++) != (c2 = *string2++) && UPPER(c1) != UPPER(c2))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|