+++ /dev/null
-/* $Id$
- *
- * Keep a cache of name/id mappings
- *
- * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
- * For copying and distribution information, please see the file
- * <mit-copyright.h>.
- */
-
-#include <mit-copyright.h>
-#include "mr_server.h"
-#include "query.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-EXEC SQL INCLUDE sqlca;
-
-RCSID("$Header$");
-
-EXEC SQL WHENEVER SQLERROR DO dbmserr();
-
-extern char *whoami;
-
-/* Cache parameters: */
-#define CACHESIZE 101 /* number of cache slots */
-
-struct item {
- char name[MAX_FIELD_WIDTH];
- enum tables type;
- int nhash;
- int id;
- struct item *next;
- struct item *prev;
- struct item *trans; /* keep track of transactions */
-};
-
-static struct item cachehead;
-static int cachesize;
-
-/* statistics counters */
-int cachehits = 0, cachemisses = 0;
-
-int hashname(char *name, enum tables type);
-
-/* Name hash function. */
-
-int hashname(char *name, enum tables type)
-{
- int val = type;
-
- while (*name)
- val = (val << 5) - val + *name++ - '`';
- return val;
-}
-
-
-/* Initialize the cache, flushing any old data, and report the statistics
- * if the cache was previously in use.
- */
-
-void flush_cache(void)
-{
- struct item *i;
-
- if (cachehits + cachemisses != 0)
- {
- com_err(whoami, 0, "Flushing cache; %d hits, %d misses, %d%% hit rate",
- cachehits, cachemisses,
- (100 * cachehits) / (cachehits + cachemisses));
- }
- else
- cachehead.next = cachehead.prev = &cachehead;
- cachehits = cachemisses = cachesize = 0;
- for (i = cachehead.next; i != &cachehead; i = i->next)
- {
- if (i->prev != &cachehead)
- free(i->prev);
- }
- if (cachehead.prev != &cachehead)
- free(cachehead.prev);
- cachehead.next = cachehead.prev = &cachehead;
- cachehead.trans = NULL;
-}
-
-
-/* Do a name to ID translation. id will be updated with the answer if
- * it is available, and as a side effect the cache is updated.
- */
-
-int name_to_id(char *name, enum tables type, int *id)
-{
- struct item *i, *t;
- EXEC SQL BEGIN DECLARE SECTION;
- char *iname;
- int j, h;
- EXEC SQL END DECLARE SECTION;
-
- h = hashname(name, type);
- for (i = cachehead.next; i != &cachehead; i = i->next)
- {
- if (i->nhash != h || strcmp(name, i->name) || type != i->type)
- continue;
- *id = i->id;
- cachehits++;
- i->next->prev = i->prev;
- i->prev->next = i->next;
- i->next = cachehead.next;
- i->prev = &cachehead;
- cachehead.next->prev = i;
- cachehead.next = i;
- return MR_SUCCESS;
- }
-
- cachemisses++;
- iname = name;
-
- switch (type)
- {
- case USERS_TABLE:
- if (strchr(iname, '@') || (strlen(iname) > 8))
- {
- sqlca.sqlcode = SQL_NO_MATCH;
- break;
- }
- EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
- break;
- case LIST_TABLE:
- EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
- break;
- case MACHINE_TABLE:
- EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
- break;
- case SUBNET_TABLE:
- EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
- break;
- case CLUSTERS_TABLE:
- EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
- break;
- case FILESYS_TABLE:
- EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
- break;
- case STRINGS_TABLE:
- if (!iname[0]) /* special-case empty string */
- {
- *id = 0;
- return MR_SUCCESS;
- }
- EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
- break;
- default:
- return MR_INTERNAL;
- }
- if (sqlca.sqlcode == SQL_NO_MATCH)
- return MR_NO_MATCH;
- if (sqlca.sqlerrd[2] > 1)
- return MR_NOT_UNIQUE;
- if (sqlca.sqlcode)
- return MR_DBMS_ERR;
- *id = j;
- if (name[0] == '#' && type != USERS_TABLE)
- return MR_SUCCESS;
- if (cachesize < CACHESIZE)
- {
- i = malloc(sizeof(struct item));
- if (!i)
- return MR_SUCCESS;
- cachesize++;
- }
- else
- {
- i = cachehead.prev;
- cachehead.prev = i->prev;
- i->prev->next = &cachehead;
- }
- strcpy(i->name, name);
- i->type = type;
- i->nhash = h;
- i->id = j;
- i->next = cachehead.next;
- i->prev = &cachehead;
- i->trans = NULL;
- cachehead.next->prev = i;
- cachehead.next = i;
- /* find the end of the transaction chain & add this item */
- for (t = &cachehead; t->trans && t != i; t = t->trans)
- ;
- if (t != i)
- t->trans = i;
- return MR_SUCCESS;
-}
-
-
-/* Perform an ID to name mapping. name should be a pointer to a pointer to
- * malloc'ed data. The buffer it refers to will be freed, and a new buffer
- * allocated with the answer.
- */
-
-int id_to_name(int id, enum tables type, char **name)
-{
- struct item *i, *t;
- EXEC SQL BEGIN DECLARE SECTION;
- char iname[MAX_FIELD_WIDTH];
- int j;
- EXEC SQL END DECLARE SECTION;
-
- for (i = cachehead.next; i != &cachehead; i = i->next)
- {
- if (i->id != id || type != i->type)
- continue;
- free(*name);
- *name = xstrdup(i->name);
- cachehits++;
- i->next->prev = i->prev;
- i->prev->next = i->next;
- i->next = cachehead.next;
- i->prev = &cachehead;
- cachehead.next->prev = i;
- cachehead.next = i;
- return MR_SUCCESS;
- }
-
- cachemisses++;
- j = id;
-
- switch (type)
- {
- case USERS_TABLE:
- EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
- break;
- case LIST_TABLE:
- EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
- break;
- case MACHINE_TABLE:
- EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
- break;
- case SUBNET_TABLE:
- EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
- break;
- case CLUSTERS_TABLE:
- EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
- break;
- case FILESYS_TABLE:
- EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
- break;
- case STRINGS_TABLE:
- EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
- break;
- default:
- return MR_INTERNAL;
- }
- if (sqlca.sqlcode == SQL_NO_MATCH)
- {
- free(*name);
- sprintf(iname, "#%d", j);
- *name = xstrdup(iname);
- return MR_NO_MATCH;
- }
- if (sqlca.sqlerrd[2] > 1)
- return MR_INTERNAL;
- if (sqlca.sqlcode)
- return MR_DBMS_ERR;
- free(*name);
- *name = xstrdup(strtrim(iname));
- if (**name == '#' && type != USERS_TABLE)
- return MR_SUCCESS;
- if (cachesize < CACHESIZE)
- {
- i = malloc(sizeof(struct item));
- if (!i)
- return MR_SUCCESS;
- cachesize++;
- }
- else
- {
- i = cachehead.prev;
- cachehead.prev = i->prev;
- i->prev->next = &cachehead;
- }
- strcpy(i->name, *name);
- i->type = type;
- i->nhash = hashname(*name, type);
- i->id = id;
- i->next = cachehead.next;
- i->prev = &cachehead;
- i->trans = NULL;
- cachehead.next->prev = i;
- cachehead.next = i;
- /* find the end of the transaction chain & add this item */
- for (t = &cachehead; t->trans && t != i; t = t->trans)
- ;
- if (t != i)
- t->trans = i;
- return MR_SUCCESS;
-}
-
-
-/* Explicitly add something to the cache without doing a lookup in the
- * database.
- */
-
-int cache_entry(char *name, enum tables type, int id)
-{
- struct item *i, *t;
-
- for (i = cachehead.next; i != &cachehead; i = i->next)
- {
- if (i->id == id && i->type == type)
- {
- if (strcmp(i->name, name))
- {
- strcpy(i->name, name);
- i->nhash = hashname(name, type);
- }
- return MR_SUCCESS;
- }
- }
- if (cachesize < CACHESIZE)
- {
- i = malloc(sizeof(struct item));
- if (!i)
- return MR_SUCCESS;
- cachesize++;
- }
- else
- {
- i = cachehead.prev;
- cachehead.prev = i->prev;
- i->prev->next = &cachehead;
- }
- strcpy(i->name, name);
- i->type = type;
- i->nhash = hashname(name, type);
- i->id = id;
- i->next = cachehead.next;
- i->prev = &cachehead;
- i->trans = NULL;
- cachehead.next->prev = i;
- cachehead.next = i;
- /* find the end of the transaction chain & add this item */
- for (t = &cachehead; t->trans && t != i; t = t->trans)
- ;
- if (t != i)
- t->trans = i;
- return MR_SUCCESS;
-}
-
-
-/* Flush something that may or may not already be in the cache. */
-
-void flush_name(char *name, enum tables type)
-{
- struct item *i;
-
- /* first clear it out of the transaction chain */
- for (i = &cachehead; i && i->trans; i = i->trans)
- {
- if (!strcmp(name, i->trans->name) && type == i->trans->type)
- i->trans = i->trans->trans;
- }
-
- /* now remove it */
- for (i = cachehead.next; i != &cachehead; i = i->next)
- {
- if (!strcmp(name, i->name) && type == i->type)
- {
- cachesize--;
- i->next->prev = i->prev;
- i->prev->next = i->next;
- free(i);
- break;
- }
- }
-}
-
-
-/* Called when a transaction is committed to also commit any cache changes.
- * Just throws away the list of cache changes for this transaction.
- */
-
-void cache_commit(void)
-{
- cachehead.trans = NULL;
-}
-
-
-/* Called whan a transaction is aborted to throw away any cache changes
- * from that transaction.
- */
-
-void cache_abort(void)
-{
- struct item *i, *t;
-
- for (i = cachehead.trans; i; i = t)
- {
- t = i->trans;
- flush_name(i->name, i->type);
- }
- cachehead.trans = NULL;
-}
mr_sqlda = mr_alloc_sqlda();
incremental_init();
- flush_cache();
}
dbms_errno = 0;
void mr_close_database(void)
{
- flush_cache();
EXEC SQL COMMIT RELEASE;
}
incremental_after(q->rtable, qual, argv_ro);
if (status != MR_SUCCESS)
break;
- flush_name(argv_ro[0], q->rtable);
table = table_name[q->rtable];
if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif"))
{
incremental_clear_after();
if (status != MR_SUCCESS)
break;
- flush_name(argv_ro[0], q->rtable);
EXEC SQL UPDATE tblstats
SET deletes = deletes + 1, modtime = SYSDATE
WHERE table_name = :table;
}
else
{
- cache_abort();
EXEC SQL ROLLBACK WORK;
incremental_flush();
}
}
- cache_commit(); /* commit following abort is safe */
if (status != MR_SUCCESS)
com_err(whoami, status, " (Query failed)");
return privileged ? MR_SUCCESS : MR_PERM;
}
-
-/* This routine caches info from the database. Each query acl is stored
- * in the query structure, and whether that acl contains everybody.
- */
-
int check_query_access(struct query *q, char *argv[], client *cl)
{
EXEC SQL BEGIN DECLARE SECTION;
if (def_uid == 0)
EXEC SQL SELECT users_id INTO :def_uid FROM users WHERE login = 'default';
- /* get query access control list */
- if (q->acl != 0)
- acl_id = q->acl;
+ name = q->shortname;
+ EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
+ if (sqlca.sqlcode < 0)
+ return MR_DBMS_ERR;
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ return MR_PERM;
+ q->acl = acl_id;
+
+ /* check for default access */
+ EXEC SQL SELECT member_id INTO :acl_id FROM imembers
+ WHERE list_id = :acl_id AND member_type = 'USER'
+ AND member_id = :def_uid;
+ if (sqlca.sqlerrd[2] == 0)
+ q->everybody = 0;
else
- {
- name = q->shortname;
- EXEC SQL SELECT list_id INTO :acl_id FROM capacls WHERE tag = :name;
- if (sqlca.sqlcode < 0)
- return MR_DBMS_ERR;
- if (sqlca.sqlcode == SQL_NO_MATCH)
- return MR_PERM;
- q->acl = acl_id;
-
- /* check for default access */
- EXEC SQL SELECT member_id INTO :acl_id FROM imembers
- WHERE list_id = :acl_id AND member_type = 'USER'
- AND member_id = :def_uid;
- if (sqlca.sqlerrd[2] == 0)
- q->everybody = 0;
- else
- q->everybody = 1;
- }
+ q->everybody = 1;
if (q->everybody)
return MR_SUCCESS;
return MR_SUCCESS;
}
+/* Do a name to ID translation. Moved from cache.pc because we did away
+ * with the cache, but what this function does is still useful to us.
+ */
+
+int name_to_id(char *name, enum tables type, int *id)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ char *iname;
+ int j;
+ EXEC SQL END DECLARE SECTION;
+
+ iname = name;
+
+ switch (type)
+ {
+ case USERS_TABLE:
+ if (strchr(iname, '@') || (strlen(iname) > 8))
+ {
+ sqlca.sqlcode = SQL_NO_MATCH;
+ break;
+ }
+ EXEC SQL SELECT users_id INTO :j FROM users WHERE login = :iname;
+ break;
+ case LIST_TABLE:
+ EXEC SQL SELECT list_id INTO :j FROM list WHERE name = :iname;
+ break;
+ case MACHINE_TABLE:
+ EXEC SQL SELECT mach_id INTO :j FROM machine WHERE name = UPPER(:iname);
+ break;
+ case SUBNET_TABLE:
+ EXEC SQL SELECT snet_id INTO :j FROM subnet WHERE name = UPPER(:iname);
+ break;
+ case CLUSTERS_TABLE:
+ EXEC SQL SELECT clu_id INTO :j FROM clusters WHERE name = :iname;
+ break;
+ case FILESYS_TABLE:
+ EXEC SQL SELECT filsys_id INTO :j FROM filesys WHERE label = :iname;
+ break;
+ case STRINGS_TABLE:
+ if (!iname[0]) /* special-case empty string */
+ {
+ *id = 0;
+ return MR_SUCCESS;
+ }
+ EXEC SQL SELECT string_id INTO :j FROM strings WHERE string = :iname;
+ break;
+ default:
+ return MR_INTERNAL;
+ }
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ return MR_NO_MATCH;
+ if (sqlca.sqlerrd[2] > 1)
+ return MR_NOT_UNIQUE;
+ if (sqlca.sqlcode)
+ return MR_DBMS_ERR;
+ *id = j;
+
+ return MR_SUCCESS;
+}
+
+/* Perform an ID to name mapping. name should be a pointer to a pointer to
+ * malloc'ed data. The buffer it refers to will be freed, and a new buffer
+ * allocated with the answer.
+ *
+ * This used to be in cache.pc, but we've removed the cache, and this function
+ * is still useful to us.
+ */
+
+int id_to_name(int id, enum tables type, char **name)
+{
+ EXEC SQL BEGIN DECLARE SECTION;
+ char iname[MAX_FIELD_WIDTH];
+ int j;
+ EXEC SQL END DECLARE SECTION;
+
+ j = id;
+
+ switch (type)
+ {
+ case USERS_TABLE:
+ EXEC SQL SELECT login INTO :iname FROM users WHERE users_id = :j;
+ break;
+ case LIST_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM list WHERE list_id = :j;
+ break;
+ case MACHINE_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM machine WHERE mach_id = :j;
+ break;
+ case SUBNET_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM subnet WHERE snet_id = :j;
+ break;
+ case CLUSTERS_TABLE:
+ EXEC SQL SELECT name INTO :iname FROM clusters WHERE clu_id = :j;
+ break;
+ case FILESYS_TABLE:
+ EXEC SQL SELECT label INTO :iname FROM filesys WHERE filsys_id = :j;
+ break;
+ case STRINGS_TABLE:
+ EXEC SQL SELECT string INTO :iname FROM strings WHERE string_id = :j;
+ break;
+ default:
+ return MR_INTERNAL;
+ }
+ if (sqlca.sqlcode == SQL_NO_MATCH)
+ {
+ free(*name);
+ sprintf(iname, "#%d", j);
+ *name = xstrdup(iname);
+ return MR_NO_MATCH;
+ }
+ if (sqlca.sqlerrd[2] > 1)
+ return MR_INTERNAL;
+ if (sqlca.sqlcode)
+ return MR_DBMS_ERR;
+ free(*name);
+ *name = xstrdup(strtrim(iname));
+
+ return MR_SUCCESS;
+}
/* eof:qrtn.dc */