8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-28 03:23:03 +01:00
firebird-mirror/src/dsql/hsh.cpp
tamlin bc383ff498 A bit const correctness added and some reinterpret_casts removed.
Changed DSQL's str to actually hold char.
2003-02-12 19:28:13 +00:00

515 lines
11 KiB
C++

/*
* PROGRAM: Dynamic SQL runtime support
* 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 "firebird.h"
#include <string.h>
#include "../dsql/dsql.h"
#include "../dsql/sym.h"
#include "../jrd/gds.h"
#include "../jrd/gds_proto.h"
#include "../dsql/alld_proto.h"
#include "../dsql/errd_proto.h"
#include "../dsql/hsh_proto.h"
#include "../jrd/sch_proto.h"
#include "../jrd/thd_proto.h"
extern "C" {
ASSERT_FILENAME
#define HASH_SIZE 211
static SSHORT hash(SCHAR *, USHORT);
static BOOLEAN remove_symbol(struct sym **, struct sym *);
static BOOLEAN scompare(TEXT *, USHORT, TEXT *, USHORT);
static SYM *hash_table;
/*
SUPERSERVER can end up with many hands in the pie, so some
protection is provided via a mutex. This ensures the integrity
of lookups, inserts and removals, and also allows teh traversing
of symbol chains for marking of relations and procedures.
Otherwise, one DSQL user won't know what the other is doing
to the same object.
*/
#ifdef SUPERSERVER
static MUTX_T hash_mutex;
static USHORT hash_mutex_inited = 0;
#define LOCK_HASH THD_mutex_lock (&hash_mutex)
#define UNLOCK_HASH THD_mutex_unlock (&hash_mutex);
#else
#define LOCK_HASH
#define UNLOCK_HASH
#endif
void HSHD_init(void)
{
/*************************************
*
* H S H D _ i n i t
*
*************************************
*
* functional description
* create a new hash table
*
************************************/
UCHAR *p;
#ifdef SUPERSERVER
if (!hash_mutex_inited) {
hash_mutex_inited = 1;
THD_mutex_init(&hash_mutex);
}
#endif
p = (UCHAR *) gds__alloc(sizeof(SYM) * HASH_SIZE);
memset(p, 0, sizeof(SYM) * HASH_SIZE);
hash_table = (SYM *) p;
}
#ifdef DEV_BUILD
#include "../jrd/ib_stdio.h"
void HSHD_debug(void)
{
/**************************************
*
* H S H D _ d e b u g
*
**************************************
*
* Functional description
* Print out the hash table for debugging.
*
**************************************/
SYM collision;
SYM homptr;
SSHORT h;
/* dump each hash table entry */
LOCK_HASH;
for (h = 0; h < HASH_SIZE; h++) {
for (collision = hash_table[h]; collision;
collision = collision->sym_collision) {
/* check any homonyms first */
ib_fprintf(ib_stderr, "Symbol type %d: %s %x\n",
collision->sym_type, collision->sym_string,
collision->sym_dbb);
for (homptr = collision->sym_homonym; homptr;
homptr = homptr->sym_homonym) {
ib_fprintf(ib_stderr, "Homonym Symbol type %d: %s %x\n",
homptr->sym_type, homptr->sym_string,
homptr->sym_dbb);
}
}
}
UNLOCK_HASH;
}
#endif
void HSHD_fini(void)
{
/**************************************
*
* H S H D _ f i n i
*
**************************************
*
* Functional description
* Clear out the symbol table. All the
* symbols are deallocated with their pools.
*
**************************************/
for (SSHORT i = 0; i < HASH_SIZE; i++)
{
hash_table[i] = NULL;
}
gds__free(hash_table);
hash_table = NULL;
}
void HSHD_finish( void *database)
{
/**************************************
*
* H S H D _ f i n i s h
*
**************************************
*
* Functional description
* Remove symbols used by a particular database.
* Don't bother to release them since their pools
* will be released.
*
**************************************/
SYM *collision;
SYM *homptr;
SYM symbol;
SYM chain;
SSHORT h;
/* check each hash table entry */
LOCK_HASH;
for (h = 0; h < HASH_SIZE; h++) {
for (collision = &hash_table[h]; *collision;) {
/* check any homonyms first */
chain = *collision;
for (homptr = &chain->sym_homonym; *homptr;) {
symbol = *homptr;
if (symbol->sym_dbb == database) {
*homptr = symbol->sym_homonym;
symbol = symbol->sym_homonym;
}
else
homptr = &symbol->sym_homonym;
}
/* now, see if the root entry has to go */
if (chain->sym_dbb == database) {
if (chain->sym_homonym) {
chain->sym_homonym->sym_collision = chain->sym_collision;
*collision = chain->sym_homonym;
}
else
*collision = chain->sym_collision;
chain = *collision;
}
else
collision = &chain->sym_collision;
}
}
UNLOCK_HASH;
}
void HSHD_insert(SYM symbol)
{
/**************************************
*
* H S H D _ i n s e r t
*
**************************************
*
* Functional description
* Insert a symbol into the hash table.
*
**************************************/
SSHORT h;
void *database;
SYM old;
LOCK_HASH;
h = hash(symbol->sym_string, symbol->sym_length);
database = symbol->sym_dbb;
assert(symbol->sym_type >= SYM_statement && symbol->sym_type <= SYM_eof);
for (old = hash_table[h]; old; old = old->sym_collision)
if ((!database || (database == old->sym_dbb)) &&
scompare(symbol->sym_string, symbol->sym_length, old->sym_string,
old->sym_length)) {
symbol->sym_homonym = old->sym_homonym;
old->sym_homonym = symbol;
UNLOCK_HASH;
return;
}
symbol->sym_collision = hash_table[h];
hash_table[h] = symbol;
UNLOCK_HASH;
}
SYM HSHD_lookup(void* database,
TEXT* string,
SSHORT length,
SYM_TYPE type,
USHORT parser_version)
{
/**************************************
*
* H S H D _ l o o k u p
*
**************************************
*
* Functional description
* Perform a string lookup against hash table.
* Make sure to only return a symbol of the desired type.
*
**************************************/
LOCK_HASH;
SSHORT h = hash(string, length);
for (SYM symbol = hash_table[h]; symbol; symbol = symbol->sym_collision)
{
if ((database == symbol->sym_dbb) &&
scompare(string, length, symbol->sym_string, symbol->sym_length))
{
/* Search for a symbol of the proper type */
while (symbol && symbol->sym_type != type) {
symbol = symbol->sym_homonym;
}
UNLOCK_HASH;
/* If the symbol found was not part of the list of keywords for the
* client connecting, then assume nothing was found
*/
if (symbol)
{
if (parser_version < symbol->sym_version &&
type == SYM_keyword)
{
return NULL;
}
}
return symbol;
}
}
UNLOCK_HASH;
return NULL;
}
void HSHD_remove( SYM symbol)
{
/**************************************
*
* H S H D _ r e m o v e
*
**************************************
*
* Functional description
* Remove a symbol from the hash table.
*
**************************************/
SYM *collision;
SSHORT h;
LOCK_HASH;
h = hash(symbol->sym_string, symbol->sym_length);
for (collision = &hash_table[h]; *collision;
collision =
&(*collision)->sym_collision) if (remove_symbol(collision, symbol)) {
UNLOCK_HASH;
return;
}
UNLOCK_HASH;
IBERROR(-1, "HSHD_remove failed");
}
void HSHD_set_flag(
void *database,
TEXT * string, SSHORT length, SYM_TYPE type, SSHORT flag)
{
/**************************************
*
* H S H D _ s e t _ f l a g
*
**************************************
*
* Functional description
* Set a flag in all similar objects in a chain. This
* is used primarily to mark relations and procedures
* as deleted. The object must have the same name and
* type, but not the same database, and must belong to
* some database. Later access to such an object by
* another user or thread should result in that object's
* being refreshed. Note that even if the relation name
* and ID, or the procedure name and ID both match, it
* may still not represent an exact match. This is because
* there's no way at present for DSQL to tell if two databases
* as represented in DSQL are attachments to the same physical
* database.
*
**************************************/
SYM symbol, homonym;
SSHORT h;
DSQL_REL sym_rel;
DSQL_PRC sym_prc;
/* as of now, there's no work to do if there is no database or if
the type is not a relation or procedure */
if (!database)
return;
switch (type) {
case SYM_relation:
case SYM_procedure:
break;
default:
return;
}
LOCK_HASH;
h = hash(string, length);
for (symbol = hash_table[h]; symbol; symbol = symbol->sym_collision) {
if (symbol->sym_dbb && (database != symbol->sym_dbb) &&
scompare(string, length, symbol->sym_string, symbol->sym_length)) {
/* the symbol name matches and it's from a different database */
for (homonym = symbol; homonym; homonym = homonym->sym_homonym) {
if (homonym->sym_type == type) {
/* the homonym is of the correct type */
/* the next check is for the same relation or procedure ID,
which indicates that it MAY be the same relation or
procedure */
switch (type) {
case SYM_relation:
sym_rel = (DSQL_REL) homonym->sym_object;
sym_rel->rel_flags |= flag;
break;
case SYM_procedure:
sym_prc = (DSQL_PRC) homonym->sym_object;
sym_prc->prc_flags |= flag;
break;
}
}
}
}
}
UNLOCK_HASH;
}
static SSHORT hash(SCHAR * string, USHORT length)
{
/**************************************
*
* h a s h
*
**************************************
*
* Functional description
* Returns the hash function of a string.
*
**************************************/
SLONG value;
SCHAR c;
value = 0;
while (length--) {
c = *string++;
value = (value << 1) + (c);
}
return ((value >= 0) ? value : -value) % HASH_SIZE;
}
static BOOLEAN remove_symbol( SYM * collision, SYM symbol)
{
/**************************************
*
* r e m o v e _ s y m b o l
*
**************************************
*
* Functional description
* Given the address of a collision,
* remove a symbol from the collision
* and homonym linked lists.
*
**************************************/
SYM *ptr, homonym;
if (symbol == *collision) {
if ((homonym = symbol->sym_homonym) != NULL) {
homonym->sym_collision = symbol->sym_collision;
*collision = homonym;
}
else
*collision = symbol->sym_collision;
return TRUE;
}
for (ptr = &(*collision)->sym_homonym; *ptr; ptr = &(*ptr)->sym_homonym)
if (symbol == *ptr) {
*ptr = symbol->sym_homonym;
return TRUE;
}
return FALSE;
}
static BOOLEAN scompare(TEXT * string1,
USHORT length1,
TEXT * string2, USHORT length2)
{
/**************************************
*
* s c o m p a r e
*
**************************************
*
* Functional description
* Compare two symbolic strings
* The character set for these strings is either ASCII or
* Unicode in UTF format.
* Symbols are case-significant - so no uppercase operation
* is performed.
*
**************************************/
if (length1 != length2)
return FALSE;
while (length1--) {
if ((*string1++) != (*string2++))
return FALSE;
}
return TRUE;
}
} // extern "C"