1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-10 17:42:29 +03:00

Postgres95 1.01 Distribution - Virgin Sources

This commit is contained in:
Marc G. Fournier
1996-07-09 06:22:35 +00:00
commit d31084e9d1
868 changed files with 242656 additions and 0 deletions

View File

@@ -0,0 +1,20 @@
#-------------------------------------------------------------------------
#
# Makefile.inc--
# Makefile for utils/adt
#
# Copyright (c) 1994, Regents of the University of California
#
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:22:02 scrappy Exp $
#
#-------------------------------------------------------------------------
SUBSRCS+= acl.c arrayfuncs.c arrayutils.c bool.c char.c chunk.c date.c \
datum.c dt.c filename.c float.c geo-ops.c geo-selfuncs.c int.c \
misc.c nabstime.c name.c not_in.c numutils.c oid.c \
oidname.c oidint2.c oidint4.c regexp.c regproc.c selfuncs.c \
tid.c varchar.c varlena.c sets.c datetimes.c like.c

618
src/backend/utils/adt/acl.c Normal file
View File

@@ -0,0 +1,618 @@
/*-------------------------------------------------------------------------
*
* acl.c--
* Basic access control list data structures manipulation routines.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.1.1.1 1996/07/09 06:22:02 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "c.h"
#include "utils/acl.h"
#include "access/htup.h"
#include "catalog/pg_user.h"
#include "utils/syscache.h"
#include "utils/elog.h"
#include "utils/palloc.h"
static char *getid(char *s, char *n);
static int32 aclitemeq(AclItem *a1, AclItem *a2);
static int32 aclitemgt(AclItem *a1, AclItem *a2);
#define ACL_IDTYPE_GID_KEYWORD "group"
#define ACL_IDTYPE_UID_KEYWORD "user"
/*
* getid
* Consumes the first alphanumeric string (identifier) found in string
* 's', ignoring any leading white space.
*
* RETURNS:
* the string position in 's' that points to the next non-space character
* in 's'. Also:
* - loads the identifier into 'name'. (If no identifier is found, 'name'
* contains an empty string).
*/
static char *
getid(char *s, char *n)
{
unsigned len;
char *id;
Assert(s && n);
while (isspace(*s))
++s;
for (id = s, len = 0; isalnum(*s); ++len, ++s)
;
if (len > sizeof(NameData))
elog(WARN, "getid: identifier cannot be >%d characters",
sizeof(NameData));
if (len > 0)
memmove(n, id, len);
n[len] = '\0';
while (isspace(*s))
++s;
return(s);
}
/*
* aclparse
* Consumes and parses an ACL specification of the form:
* [group|user] [A-Za-z0-9]*[+-=][rwaR]*
* from string 's', ignoring any leading white space or white space
* between the optional id type keyword (group|user) and the actual
* ACL specification.
*
* This routine is called by the parser as well as aclitemin(), hence
* the added generality.
*
* RETURNS:
* the string position in 's' immediately following the ACL
* specification. Also:
* - loads the structure pointed to by 'aip' with the appropriate
* UID/GID, id type identifier and mode type values.
* - loads 'modechg' with the mode change flag.
*/
char *
aclparse(char *s, AclItem *aip, unsigned *modechg)
{
HeapTuple htp;
char name[NAMEDATALEN+1];
extern AclId get_grosysid();
Assert(s && aip && modechg);
aip->ai_idtype = ACL_IDTYPE_UID;
s = getid(s, name);
if (*s != ACL_MODECHG_ADD_CHR &&
*s != ACL_MODECHG_DEL_CHR &&
*s != ACL_MODECHG_EQL_CHR)
{ /* we just read a keyword, not a name */
if (!strcmp(name, ACL_IDTYPE_GID_KEYWORD)) {
aip->ai_idtype = ACL_IDTYPE_GID;
} else if (strcmp(name, ACL_IDTYPE_UID_KEYWORD)) {
elog(WARN, "aclparse: bad keyword, must be [group|user]");
}
s = getid(s, name); /* move s to the name beyond the keyword */
if (name[0] == '\0')
elog(WARN, "aclparse: a name must follow the [group|user] keyword");
}
if (name[0] == '\0')
aip->ai_idtype = ACL_IDTYPE_WORLD;
switch (*s) {
case ACL_MODECHG_ADD_CHR: *modechg = ACL_MODECHG_ADD; break;
case ACL_MODECHG_DEL_CHR: *modechg = ACL_MODECHG_DEL; break;
case ACL_MODECHG_EQL_CHR: *modechg = ACL_MODECHG_EQL; break;
default: elog(WARN, "aclparse: mode change flag must use \"%s\"",
ACL_MODECHG_STR);
}
aip->ai_mode = ACL_NO;
while (isalpha(*++s)) {
switch (*s) {
case ACL_MODE_AP_CHR: aip->ai_mode |= ACL_AP; break;
case ACL_MODE_RD_CHR: aip->ai_mode |= ACL_RD; break;
case ACL_MODE_WR_CHR: aip->ai_mode |= ACL_WR; break;
case ACL_MODE_RU_CHR: aip->ai_mode |= ACL_RU; break;
default: elog(WARN, "aclparse: mode flags must use \"%s\"",
ACL_MODE_STR);
}
}
switch (aip->ai_idtype) {
case ACL_IDTYPE_UID:
htp = SearchSysCacheTuple(USENAME, PointerGetDatum(name),
0,0,0);
if (!HeapTupleIsValid(htp))
elog(WARN, "aclparse: non-existent user \"%s\"", name);
aip->ai_id = ((Form_pg_user) GETSTRUCT(htp))->usesysid;
break;
case ACL_IDTYPE_GID:
aip->ai_id = get_grosysid(name);
break;
case ACL_IDTYPE_WORLD:
aip->ai_id = ACL_ID_WORLD;
break;
}
#ifdef ACLDEBUG_TRACE
elog(DEBUG, "aclparse: correctly read [%x %d %x], modechg=%x",
aip->ai_idtype, aip->ai_id, aip->ai_mode, *modechg);
#endif
return(s);
}
/*
* makeacl
* Allocates storage for a new Acl with 'n' entries.
*
* RETURNS:
* the new Acl
*/
Acl *
makeacl(int n)
{
Acl *new_acl;
Size size;
if (n < 0)
elog(WARN, "makeacl: invalid size: %d\n", n);
size = ACL_N_SIZE(n);
if (!(new_acl = (Acl *) palloc(size)))
elog(WARN, "makeacl: palloc failed on %d\n", size);
memset((char *) new_acl, 0, size);
new_acl->size = size;
new_acl->ndim = 1;
new_acl->flags = 0;
ARR_LBOUND(new_acl)[0] = 0;
ARR_DIMS(new_acl)[0] = n;
return(new_acl);
}
/*
* aclitemin
* Allocates storage for, and fills in, a new AclItem given a string
* 's' that contains an ACL specification. See aclparse for details.
*
* RETURNS:
* the new AclItem
*/
AclItem *
aclitemin(char *s)
{
unsigned modechg;
AclItem *aip;
if (!s)
elog(WARN, "aclitemin: null string");
aip = (AclItem *) palloc(sizeof(AclItem));
if (!aip)
elog(WARN, "aclitemin: palloc failed");
s = aclparse(s, aip, &modechg);
if (modechg != ACL_MODECHG_EQL)
elog(WARN, "aclitemin: cannot accept anything but = ACLs");
while (isspace(*s))
++s;
if (*s)
elog(WARN, "aclitemin: extra garbage at end of specification");
return(aip);
}
/*
* aclitemout
* Allocates storage for, and fills in, a new null-delimited string
* containing a formatted ACL specification. See aclparse for details.
*
* RETURNS:
* the new string
*/
char *
aclitemout(AclItem *aip)
{
register char *p;
char *out;
HeapTuple htp;
unsigned i;
static AclItem default_aclitem = { ACL_ID_WORLD,
ACL_IDTYPE_WORLD,
ACL_WORLD_DEFAULT };
extern char *int2out();
char *tmpname;
if (!aip)
aip = &default_aclitem;
p = out = palloc(strlen("group =arwR ") + 1 + NAMEDATALEN);
if (!out)
elog(WARN, "aclitemout: palloc failed");
*p = '\0';
switch (aip->ai_idtype) {
case ACL_IDTYPE_UID:
htp = SearchSysCacheTuple(USESYSID, ObjectIdGetDatum(aip->ai_id),
0,0,0);
if (!HeapTupleIsValid(htp)) {
char *tmp = int2out(aip->ai_id);
elog(NOTICE, "aclitemout: usesysid %d not found",
aip->ai_id);
(void) strcat(p, tmp);
pfree(tmp);
} else
(void) strncat(p, (char *) &((Form_pg_user)
GETSTRUCT(htp))->usename,
sizeof(NameData));
break;
case ACL_IDTYPE_GID:
(void) strcat(p, "group ");
tmpname = get_groname(aip->ai_id);
(void) strncat(p, tmpname, NAMEDATALEN);
pfree(tmpname);
break;
case ACL_IDTYPE_WORLD:
break;
default:
elog(WARN, "aclitemout: bad ai_idtype: %d", aip->ai_idtype);
break;
}
while (*p)
++p;
*p++ = '=';
for (i = 0; i < N_ACL_MODES; ++i)
if ((aip->ai_mode >> i) & 01)
*p++ = ACL_MODE_STR[i];
*p = '\0';
return(out);
}
/*
* aclitemeq
* aclitemgt
* AclItem equality and greater-than comparison routines.
* Two AclItems are equal iff they are both NULL or they have the
* same identifier (and identifier type).
*
* RETURNS:
* a boolean value indicating = or >
*/
static int32
aclitemeq(AclItem *a1, AclItem *a2)
{
if (!a1 && !a2)
return(1);
if (!a1 || !a2)
return(0);
return(a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id);
}
static int32
aclitemgt(AclItem *a1, AclItem *a2)
{
if (a1 && !a2)
return(1);
if (!a1 || !a2)
return(0);
return((a1->ai_idtype > a2->ai_idtype) ||
(a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
}
Acl *
aclownerdefault(AclId ownerid)
{
Acl *acl;
AclItem *aip;
acl = makeacl(2);
aip = ACL_DAT(acl);
aip[0].ai_idtype = ACL_IDTYPE_WORLD;
aip[0].ai_id = ACL_ID_WORLD;
aip[0].ai_mode = ACL_WORLD_DEFAULT;
aip[1].ai_idtype = ACL_IDTYPE_UID;
aip[1].ai_id = ownerid;
aip[1].ai_mode = ACL_OWNER_DEFAULT;
return(acl);
}
Acl *
acldefault()
{
Acl *acl;
AclItem *aip;
acl = makeacl(1);
aip = ACL_DAT(acl);
aip[0].ai_idtype = ACL_IDTYPE_WORLD;
aip[0].ai_id = ACL_ID_WORLD;
aip[0].ai_mode = ACL_WORLD_DEFAULT;
return(acl);
}
Acl *
aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
{
Acl *new_acl;
AclItem *old_aip, *new_aip;
unsigned src, dst, num;
if (!old_acl || ACL_NUM(old_acl) < 1) {
new_acl = makeacl(0);
return(new_acl);
}
if (!mod_aip) {
new_acl = makeacl(ACL_NUM(old_acl));
memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
return(new_acl);
}
num = ACL_NUM(old_acl);
old_aip = ACL_DAT(old_acl);
/*
* Search the ACL for an existing entry for 'id'. If one exists,
* just modify the entry in-place (well, in the same position, since
* we actually return a copy); otherwise, insert the new entry in
* sort-order.
*/
/* find the first element not less than the element to be inserted */
for (dst = 0; dst < num && aclitemgt(mod_aip, old_aip+dst); ++dst)
;
if (dst < num && aclitemeq(mod_aip, old_aip+dst)) {
/* modify in-place */
new_acl = makeacl(ACL_NUM(old_acl));
memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
new_aip = ACL_DAT(new_acl);
src = dst;
} else {
new_acl = makeacl(num + 1);
new_aip = ACL_DAT(new_acl);
if (dst == 0) { /* start */
elog(WARN, "aclinsert3: insertion before world ACL??");
} else if (dst >= num) { /* end */
memmove((char *) new_aip,
(char *) old_aip,
num * sizeof(AclItem));
} else { /* middle */
memmove((char *) new_aip,
(char *) old_aip,
dst * sizeof(AclItem));
memmove((char *) (new_aip+dst+1),
(char *) (old_aip+dst),
(num - dst) * sizeof(AclItem));
}
new_aip[dst].ai_id = mod_aip->ai_id;
new_aip[dst].ai_idtype = mod_aip->ai_idtype;
num++; /* set num to the size of new_acl */
src = 0; /* world entry */
}
switch (modechg) {
case ACL_MODECHG_ADD: new_aip[dst].ai_mode =
old_aip[src].ai_mode | mod_aip->ai_mode;
break;
case ACL_MODECHG_DEL: new_aip[dst].ai_mode =
old_aip[src].ai_mode & ~mod_aip->ai_mode;
break;
case ACL_MODECHG_EQL: new_aip[dst].ai_mode =
mod_aip->ai_mode;
break;
}
/* if the newly added entry has no permissions, delete it from
the list. For example, this helps in removing entries for users who
no longer exists...*/
for (dst = 1; dst < num; dst++) {
if (new_aip[dst].ai_mode == 0) {
int i;
for (i=dst+1; i<num; i++) {
new_aip[i-1].ai_id = new_aip[i].ai_id;
new_aip[i-1].ai_idtype = new_aip[i].ai_idtype;
new_aip[i-1].ai_mode = new_aip[i].ai_mode;
}
ARR_DIMS(new_acl)[0] = num -1 ;
break;
}
}
return(new_acl);
}
/*
* aclinsert
*
*/
Acl *
aclinsert(Acl *old_acl, AclItem *mod_aip)
{
return(aclinsert3(old_acl, mod_aip, ACL_MODECHG_EQL));
}
Acl *
aclremove(Acl *old_acl, AclItem *mod_aip)
{
Acl *new_acl;
AclItem *old_aip, *new_aip;
unsigned dst, old_num, new_num;
if (!old_acl || ACL_NUM(old_acl) < 1) {
new_acl = makeacl(0);
return(new_acl);
}
if (!mod_aip) {
new_acl = makeacl(ACL_NUM(old_acl));
memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
return(new_acl);
}
old_num = ACL_NUM(old_acl);
old_aip = ACL_DAT(old_acl);
for (dst = 0; dst < old_num && !aclitemeq(mod_aip, old_aip+dst); ++dst)
;
if (dst >= old_num) { /* not found or empty */
new_acl = makeacl(ACL_NUM(old_acl));
memmove((char *) new_acl, (char *) old_acl, ACL_SIZE(old_acl));
} else {
new_num = old_num - 1;
new_acl = makeacl(ACL_NUM(old_acl) - 1);
new_aip = ACL_DAT(new_acl);
if (dst == 0) { /* start */
elog(WARN, "aclremove: removal of the world ACL??");
} else if (dst == old_num - 1) {/* end */
memmove((char *) new_aip,
(char *) old_aip,
new_num * sizeof(AclItem));
} else { /* middle */
memmove((char *) new_aip,
(char *) old_aip,
dst * sizeof(AclItem));
memmove((char *) (new_aip+dst),
(char *) (old_aip+dst+1),
(new_num - dst) * sizeof(AclItem));
}
}
return(new_acl);
}
int32
aclcontains(Acl *acl, AclItem *aip)
{
unsigned i, num;
AclItem *aidat;
if (!acl || !aip || ((num = ACL_NUM(acl)) < 1))
return(0);
aidat = ACL_DAT(acl);
for (i = 0; i < num; ++i)
if (aclitemeq(aip, aidat+i))
return(1);
return(0);
}
/* parser support routines */
/*
* aclmakepriv
* make a acl privilege string out of an existing privilege string
* and a new privilege
*
* does not add duplicate privileges
*
* the CALLER is reponsible for free'ing the string returned
*/
char*
aclmakepriv(char* old_privlist, char new_priv)
{
char* priv;
int i;
int l;
Assert(strlen(old_privlist)<5);
priv = malloc(5); /* at most "rwaR" */;
if (old_privlist == NULL || old_privlist[0] == '\0') {
priv[0] = new_priv;
priv[1] = '\0';
return priv;
}
strcpy(priv,old_privlist);
l = strlen(old_privlist);
if (l == 4) { /* can't add any more privileges */
return priv;
}
/* check to see if the new privilege is already in the old string */
for (i=0;i<l;i++) {
if (priv[i] == new_priv)
break;
}
if (i == l) { /* we really have a new privilege*/
priv[l] = new_priv;
priv[l+1] = '\0';
}
return priv;
}
/*
* aclmakeuser
* user_type must be "A" - all users
* "G" - group
* "U" - user
*
* concatentates the two strings together with a space in between
*
* this routine is used in the parser
*
* the CALLER is responsible for freeing the memory allocated
*/
char*
aclmakeuser(char* user_type, char* user)
{
char* user_list;
user_list = malloc(strlen(user) + 3);
sprintf(user_list, "%s %s", user_type, user);
return user_list;
}
/*
* makeAclStmt:
* this is a helper routine called by the parser
* create a ChangeAclStmt
* we take in the privilegs, relation_name_list, and grantee
* as well as a single character '+' or '-' to indicate grant or revoke
*
* returns a new ChangeACLStmt*
*
* this routines works by creating a old-style changle acl string and
* then calling aclparse;
*/
ChangeACLStmt*
makeAclStmt(char* privileges, List* rel_list, char* grantee,
char grant_or_revoke)
{
ChangeACLStmt *n = makeNode(ChangeACLStmt);
char str[MAX_PARSE_BUFFER];
n->aclitem = (AclItem*)palloc(sizeof(AclItem));
/* the grantee string is "G <group_name>", "U <user_name>", or "ALL" */
if (grantee[0] == 'G') /* group permissions */
{
sprintf(str,"%s %s%c%s",
ACL_IDTYPE_GID_KEYWORD,
grantee+2, grant_or_revoke,privileges);
}
else if (grantee[0] == 'U') /* user permission */
{
sprintf(str,"%s %s%c%s",
ACL_IDTYPE_UID_KEYWORD,
grantee+2, grant_or_revoke,privileges);
}
else /* all permission */
{
sprintf(str,"%c%s",
grant_or_revoke,privileges);
}
n->relNames = rel_list;
aclparse(str, n->aclitem, (unsigned*)&n->modechg);
return n;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,111 @@
/*-------------------------------------------------------------------------
*
* arrayutils.c--
* This file contains some support routines required for array functions.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/arrayutils.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#define WEAK_C_OPTIMIZER
#include "c.h"
int
GetOffset(int n, int dim[], int lb[], int indx[])
{
int i, scale, offset;
for (i = n-1, scale = 1, offset = 0; i >= 0; scale*=dim[i--])
offset += (indx[i] - lb[i])*scale;
return offset ;
}
int
getNitems(int n, int a[])
{
int i, ret;
for (i = 0, ret = 1; i < n; ret *= a[i++]);
if (n == 0) ret = 0;
return ret;
}
int
compute_size(int st[], int endp[], int n, int base)
{
int i, ret;
for (i = 0, ret = base; i < n; i++)
ret *= (endp[i] - st[i] + 1);
return ret;
}
void
mda_get_offset_values(int n, int dist[], int PC[], int span[])
{
int i, j;
for (j = n-2, dist[n-1]=0; j >= 0; j--)
for (i = j+1, dist[j] = PC[j]-1; i < n;
dist[j] -= (span[i] - 1)*PC[i], i++);
}
void
mda_get_range(int n, int span[], int st[], int endp[])
{
int i;
for (i= 0; i < n; i++)
span[i] = endp[i] - st[i] + 1;
}
void
mda_get_prod(int n, int range[], int P[])
{
int i;
for (i= n-2, P[n-1] = 1; i >= 0; i--)
P[i] = P[i+1] * range[i + 1];
}
int
tuple2linear(int n, int tup[], int scale[])
{
int i, lin;
for (i= lin = 0; i < n; i++)
lin += tup[i]*scale[i];
return lin;
}
void
array2chunk_coord(int n, int C[], int a_coord[], int c_coord[])
{
int i;
for (i= 0; i < n; i++)
c_coord[i] = a_coord[i]/C[i];
}
/*-----------------------------------------------------------------------------
generates the tuple that is lexicographically one greater than the current
n-tuple in "curr", with the restriction that the i-th element of "curr" is
less than the i-th element of "span".
RETURNS 0 if no next tuple exists
1 otherwise
-----------------------------------------------------------------------------*/
int
next_tuple(int n, int curr[], int span[])
{
int i;
if (!n) return(-1);
curr[n-1] = (curr[n-1]+1)%span[n-1];
for (i = n-1; i*(!curr[i]); i--)
curr[i-1] = (curr[i-1]+1)%span[i-1];
if (i)
return(i);
if (curr[0])
return(0);
return(-1);
}

View File

@@ -0,0 +1,65 @@
/*-------------------------------------------------------------------------
*
* bool.c--
* Functions for the built-in type "bool".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/bool.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/builtins.h" /* where the declarations go */
#include "utils/elog.h"
#include "utils/palloc.h"
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* boolin - converts "t" or "f" to 1 or 0
*/
int32
boolin(char *b)
{
if (b == NULL)
elog(WARN, "Bad input string for type bool");
return((int32) (*b == 't') || (*b == 'T'));
}
/*
* boolout - converts 1 or 0 to "t" or "f"
*/
char *
boolout(long b)
{
char *result = (char *) palloc(2);
*result = (b) ? 't' : 'f';
result[1] = '\0';
return(result);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
int32
booleq(int8 arg1, int8 arg2)
{
return(arg1 == arg2);
}
int32
boolne(int8 arg1, int8 arg2)
{
return(arg1 != arg2);
}

View File

@@ -0,0 +1,392 @@
/*-------------------------------------------------------------------------
*
* char.c--
* Functions for the built-in type "char".
* Functions for the built-in type "cid".
* Functions for the built-in type "char2".
* Functions for the built-in type "char4".
* Functions for the built-in type "char8".
* Functions for the built-in type "char16".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/char.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where the declarations go */
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* charin - converts "x" to 'x'
*/
int32 charin(char *ch)
{
if (ch == NULL)
return((int32) NULL);
return((int32) *ch);
}
/*
* charout - converts 'x' to "x"
*/
char *charout(int32 ch)
{
char *result = (char *) palloc(2);
result[0] = (char) ch;
result[1] = '\0';
return(result);
}
/*
* cidin - converts "..." to internal representation.
*
* NOTE: we must not use 'charin' because cid might be a non
* printable character...
*/
int32 cidin(char *s)
{
CommandId c;
if (s==NULL)
c = 0;
else
c = atoi(s);
return((int32)c);
}
/*
* cidout - converts a cid to "..."
*
* NOTE: we must no use 'charout' because cid might be a non
* printable character...
*/
char *cidout(int32 c)
{
char *result;
CommandId c2;
/*
* cid is a number between 0 .. 2^16-1, therefore we need at most
* 6 chars for the string (5 digits + '\0')
* NOTE: print it as an UNSIGNED int!
*/
result = palloc(6);
c2 = (CommandId)c;
sprintf(result, "%u", (unsigned)(c2));
return(result);
}
/*
* char16in - converts "..." to internal reprsentation
*
* Note:
* Currently if strlen(s) < 14, the extra chars are nulls
*/
char *char16in(char *s)
{
char *result;
if (s == NULL)
return(NULL);
result = (char *) palloc(16);
memset(result, 0, 16);
(void) strncpy(result, s, 16);
return(result);
}
/*
* char16out - converts internal reprsentation to "..."
*/
char *char16out(char *s)
{
char *result = (char *) palloc(17);
memset(result, 0, 17);
if (s == NULL) {
result[0] = '-';
} else {
strncpy(result, s, 16);
}
return(result);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
int32 chareq(int8 arg1, int8 arg2) { return(arg1 == arg2); }
int32 charne(int8 arg1, int8 arg2) { return(arg1 != arg2); }
int32 charlt(int8 arg1, int8 arg2) { return(arg1 < arg2); }
int32 charle(int8 arg1, int8 arg2) { return(arg1 <= arg2); }
int32 chargt(int8 arg1, int8 arg2) { return(arg1 > arg2); }
int32 charge(int8 arg1, int8 arg2) { return(arg1 >= arg2); }
int8 charpl(int8 arg1, int8 arg2) { return(arg1 + arg2); }
int8 charmi(int8 arg1, int8 arg2) { return(arg1 - arg2); }
int8 charmul(int8 arg1, int8 arg2) { return(arg1 * arg2); }
int8 chardiv(int8 arg1, int8 arg2) { return(arg1 / arg2); }
int32 cideq(int8 arg1, int8 arg2) { return(arg1 == arg2); }
/*
* char16eq - returns 1 iff arguments are equal
* char16ne - returns 1 iff arguments are not equal
*
* BUGS:
* Assumes that "xy\0\0a" should be equal to "xy\0b".
* If not, can do the comparison backwards for efficiency.
*
* char16lt - returns 1 iff a < b
* char16le - returns 1 iff a <= b
* char16gt - returns 1 iff a < b
* char16ge - returns 1 iff a <= b
*
*/
int32 char16eq(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 16) == 0);
}
int32 char16ne(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 16) != 0);
}
int32 char16lt(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1, arg2, 16) < 0));
}
int32 char16le(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1, arg2, 16) <= 0));
}
int32 char16gt(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1, arg2, 16) > 0));
}
int32 char16ge(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1, arg2, 16) >= 0));
}
/* ============================== char2 ============================== */
uint16 char2in(char *s)
{
uint16 res;
if (s == NULL)
return(0);
memset((char *) &res, 0, sizeof(res));
(void) strncpy((char *) &res, s, 2);
return(res);
}
char *char2out(uint16 s)
{
char *result = (char *) palloc(3);
memset(result, 0, 3);
(void) strncpy(result, (char *) &s, 2);
return(result);
}
int32 char2eq(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) == 0);
}
int32 char2ne(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) != 0);
}
int32 char2lt(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) < 0);
}
int32 char2le(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) <= 0);
}
int32 char2gt(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) > 0);
}
int32 char2ge(uint16 a, uint16 b)
{
return(strncmp((char *) &a, (char *) &b, 2) >= 0);
}
int32 char2cmp(uint16 a, uint16 b)
{
return (strncmp((char *) &a, (char *) &b, 2));
}
/* ============================== char4 ============================== */
uint32 char4in(char *s)
{
uint32 res;
if (s == NULL)
return(0);
memset((char *) &res, 0, sizeof(res));
(void) strncpy((char *) &res, s, 4);
return(res);
}
char *char4out(s)
uint32 s;
{
char *result = (char *) palloc(5);
memset(result, 0, 5);
(void) strncpy(result, (char *) &s, 4);
return(result);
}
int32 char4eq(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) == 0);
}
int32 char4ne(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) != 0);
}
int32 char4lt(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) < 0);
}
int32 char4le(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) <= 0);
}
int32 char4gt(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) > 0);
}
int32 char4ge(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4) >= 0);
}
int32 char4cmp(uint32 a, uint32 b)
{
return(strncmp((char *) &a, (char *) &b, 4));
}
/* ============================== char8 ============================== */
char *char8in(char *s)
{
char *result;
if (s == NULL)
return((char *) NULL);
result = (char *) palloc(8);
memset(result, 0, 8);
(void) strncpy(result, s, 8);
return(result);
}
char *char8out(char *s)
{
char *result = (char *) palloc(9);
memset(result, 0, 9);
if (s == NULL) {
result[0] = '-';
} else {
strncpy(result, s, 8);
}
return(result);
}
int32 char8eq(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) == 0);
}
int32 char8ne(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) != 0);
}
int32 char8lt(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) < 0);
}
int32 char8le(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) <= 0);
}
int32 char8gt(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) > 0);
}
int32 char8ge(char *arg1, char *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1, arg2, 8) >= 0);
}
int32 char8cmp(char *arg1, char *arg2)
{
return(strncmp(arg1, arg2, 8));
}

View File

@@ -0,0 +1,587 @@
/*-------------------------------------------------------------------------
*
* chunk.c--
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/chunk.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include "postgres.h"
#include "utils/memutils.h"
#include "libpq/libpq-fs.h"
#include "storage/fd.h" /* for SEEK_ */
#include "catalog/pg_type.h"
#include "utils/palloc.h"
#include "fmgr.h"
#include "utils/elog.h"
#include "utils/array.h"
#include "optimizer/internal.h"
#define INFTY 500000000
#define MANY 10000
#define MAXPAT 20
#define quot_ceil(x,y) (((x)+(y)-1)/(y))
#define min(x,y) (((x) < (y))? (x) : (y))
#define max(x,y) (((x) > (y))? (x) : (y))
static CHUNK_INFO cInfo;
/* non-export function prototypes */
static int _FindBestChunk(int size, int dmax[], int dbest[], int dim,
int A[MAXPAT][MAXDIM+1], int N);
static int get_next(int d[], int k, int C, int dmax[]);
static void initialize_info(CHUNK_INFO *A, int ndim, int dim[], int chunk[]);
static void _ConvertToChunkFile(int n, int baseSize, int dim[], int C[],
int srcfd, int destfd);
static void read_chunk(int chunk_no[], int C[], char a_chunk[], int srcfd,
int n, int baseSize, int PX[], int dist[]);
static int write_chunk(struct varlena * a_chunk, int ofile);
static int seek_and_read(int pos, int size, char buff[], int fp, int from);
/*------------------------------------------------------------------------
* _ChunkArray ---
* converts an input array to chunked format using the information
* provided by the access pattern.
* Results:
* creates a new file that stores the chunked array and returns
* information about the chunked file
*-----------------------------------------------------------------------
*/
char *
_ChunkArray(int fd,
FILE *afd,
int ndim,
int dim[],
int baseSize,
int *nbytes,
char *chunkfile)
{
int cfd;
int chunk[MAXDIM], csize;
bool reorgFlag;
if (chunkfile == NULL)
reorgFlag = true;
else
reorgFlag = false;
#ifdef LOARRAY
if (reorgFlag)
/* create new LO for chunked file */
chunkfile = _array_newLO( &cfd, fileFlag );
else
cfd = LOopen(chunkfile, O_RDONLY);
#endif
if (cfd < 0)
elog(WARN, "Enable to open chunk file");
strcpy (cInfo.lo_name, chunkfile);
/* find chunk size */
csize = GetChunkSize(afd, ndim, dim, baseSize, chunk);
if (reorgFlag)
/* copy data from input file to chunked file */
_ConvertToChunkFile(ndim, baseSize, dim, chunk, fd, cfd);
initialize_info(&cInfo, ndim, dim, chunk);
*nbytes = sizeof(CHUNK_INFO);
return (char *) &cInfo ;
}
/*--------------------------------------------------------------------------
* GetChunkSize --
* given an access pattern and array dimensionality etc, this program
* returns the dimensions of the chunk in "d"
*-----------------------------------------------------------------------
*/
int
GetChunkSize(FILE *fd,
int ndim,
int dim[MAXDIM],
int baseSize,
int d[MAXDIM])
{
int N, i, j, csize;
int A[MAXPAT][MAXDIM+1], dmax[MAXDIM];
/*
* ----------- read input ------------
*/
fscanf(fd, "%d", &N);
if ( N > MAXPAT )
elog(WARN, "array_in: too many access pattern elements");
for (i = 0; i < N; i++)
for (j = 0; j < ndim+1; j++)
if (fscanf(fd, "%d ", &(A[i][j])) == EOF)
elog (WARN, "array_in: bad access pattern input");
/*
* estimate chunk size
*/
for (i = 0; i < ndim; i++)
for (j = 0, dmax[i] = 1; j < N; j++)
if (dmax[i] < A[j][i])
dmax[i] = A[j][i];
csize = _PAGE_SIZE_/baseSize;
_FindBestChunk (csize, dmax, d, ndim, A, N);
return csize;
}
/*-------------------------------------------------------------------------
* _FindBestChunk --
* This routine does most of the number crunching to compute the
* optimal chunk shape.
* Called by GetChunkSize
*------------------------------------------------------------------------
*/
static int
_FindBestChunk(int size,
int dmax[],
int dbest[],
int dim,
int A[MAXPAT][MAXDIM+1],
int N)
{
int d[MAXDIM];
int tc, mintc = INFTY;
d[0] = 0;
mintc = INFTY;
while (get_next(d,dim,size, dmax)) {
/*
* compute the number of page fetches for a given
* chunk size (d[]) and access pattern (A[][])
*/
register int i,j, nc;
for (i = 0, tc = 0; i < N; i++){
for (j = 0, nc = 1; j < dim; j++)
nc *= quot_ceil(A[i][j], d[j]);
nc *= A[i][dim];
tc += nc;
}
/*
* tc holds the total number of page fetches
*/
if (mintc >= tc) {
mintc = tc;
for (j = 0; j < dim; dbest[j] = d[j], j++)
;
}
}
return(mintc);
}
/*----------------------------------------------------------------------
* get_next --
* Called by _GetBestChunk to get the next tuple in the lexicographic order
*---------------------------------------------------------------------
*/
static int
get_next(int d[], int k, int C, int dmax[])
{
register int i,j, temp;
if (!d[0]) {
temp = C;
for (j = k-1; j >= 0; j--){
d[j] = min(temp, dmax[j]);
temp = max(1, temp/d[j]);
}
return(1);
}
for (j = 0, temp = 1; j < k; j++)
temp *= d[j];
for (i=k-1; i >= 0; i--){
temp = temp/d[i];
if (((temp*(d[i]+1)) < C) && (d[i]+1 <= dmax[i]))
break;
}
if (i < 0)
return(0);
d[i]++;
j = C/temp;
d[i] = min(dmax[i], j/(j/d[i]));
temp = temp*d[i];
temp = C/temp;
for (j = k-1; j > i; j--){
d[j] = min(temp, dmax[j]);
temp = max(1, temp/d[j]);
}
return(1);
}
static char a_chunk[_PAGE_SIZE_ + 4]; /* 4 since a_chunk is in
varlena format */
static void
initialize_info(CHUNK_INFO *A, int ndim, int dim[], int chunk[])
{
int i;
for ( i = 0; i < ndim; i++)
A->C[i] = chunk[i];
}
/*--------------------------------------------------------------------------
* Procedure reorganize_data():
* This procedure reads the input multidimensional array that is organised
* in the order specified by array "X" and breaks it up into chunks of
* dimensions specified in "C".
*
* This is a very slow process, since reading and writing of LARGE files
* may be involved.
*
*-------------------------------------------------------------------------
*/
static void
_ConvertToChunkFile(int n,
int baseSize,
int dim[],
int C[],
int srcfd,
int destfd)
{
int max_chunks[MAXDIM], chunk_no[MAXDIM];
int PX[MAXDIM], dist[MAXDIM];
int csize = 1, i, temp;
for (i = 0; i < n; chunk_no[i++] = 0) {
max_chunks[i] = dim[i]/C[i];
csize *= C[i];
}
csize *= baseSize;
temp = csize + 4;
memmove(a_chunk, &temp, 4);
mda_get_prod(n, dim, PX);
mda_get_offset_values(n, dist, PX, C);
for (i = 0; i < n; dist[i] *= baseSize, i++)
;
do {
read_chunk(chunk_no, C, &(a_chunk[4]), srcfd, n, baseSize, PX, dist);
write_chunk((struct varlena*)a_chunk, destfd);
} while (next_tuple(n, chunk_no, max_chunks) != -1);
}
/*--------------------------------------------------------------------------
* read_chunk
* reads a chunk from the input files into a_chunk, the position of the
* chunk is specified by chunk_no
*--------------------------------------------------------------------------
*/
static void
read_chunk(int chunk_no[],
int C[],
char a_chunk[],
int srcfd,
int n,
int baseSize,
int PX[],
int dist[])
{
int i, j, cp, unit_transfer;
int start_pos, pos[MAXDIM];
int indx[MAXDIM];
int fpOff;
for ( i = start_pos = 0; i < n; i++) {
pos[i] = chunk_no[i] * C[i];
start_pos += pos[i]*PX[i];
}
start_pos *= baseSize;
/* Read a block of dimesion C starting at co-ordinates pos */
unit_transfer = C[n-1] * baseSize;
for (i = 0; i < n; indx[i++] = 0)
;
fpOff = start_pos;
seek_and_read(fpOff, unit_transfer, a_chunk, srcfd, SEEK_SET);
fpOff += unit_transfer;
cp = unit_transfer;
while ((j = next_tuple(n-1, indx, C)) != -1) {
fpOff += dist[j];
seek_and_read(fpOff, unit_transfer, &(a_chunk[cp]), srcfd, SEEK_SET);
cp += unit_transfer;
fpOff += unit_transfer;
}
}
/*--------------------------------------------------------------------------
* write_chunk()
* writes a chunk of size csize into the output file
*--------------------------------------------------------------------------
*/
static int
write_chunk(struct varlena * a_chunk, int ofile)
{
int got_n;
#ifdef LOARRAY
got_n = LOwrite (ofile, a_chunk);
#endif
return(got_n);
}
/*--------------------------------------------------------------------------
* seek_and_read()
* seeks to the asked location in the input file and reads the
* appropriate number of blocks
* Called By: read_chunk()
*--------------------------------------------------------------------------
*/
static int
seek_and_read(int pos, int size, char buff[], int fp, int from)
{
struct varlena *v;
/* Assuming only one file */
if ( lo_lseek(fp, pos, from ) < 0)
elog(WARN, "File seek error");
#ifdef LOARRAY
v = (struct varlena *) LOread(fp, size);
#endif
if (VARSIZE(v) - 4 < size)
elog(WARN, "File read error");
memmove(buff, VARDATA(v), size);
pfree(v);
return(1);
}
/*----------------------------------------------------------------------------
* _ReadChunkArray --
* returns the subarray specified bu the range indices "st" and "endp"
* from the chunked array stored in file "fp"
*---------------------------------------------------------------------------
*/
int
_ReadChunkArray(int st[],
int endp[],
int bsize,
int fp,
char *destfp,
ArrayType *array,
int isDestLO,
bool *isNull)
{
int i,j,jj;
int n, temp, words_read;
int chunk_span[MAXDIM], chunk_off[MAXDIM];
int chunk_st[MAXDIM], chunk_end[MAXDIM];
int block_seek;
int bptr, *C, csize, *dim, *lb;
int range_st[MAXDIM], range_end[MAXDIM],
range[MAXDIM], array_span[MAXDIM];
int PA[MAXDIM], PCHUNK[MAXDIM], PC[MAXDIM];
int to_read;
int cdist[MAXDIM], adist[MAXDIM];
int dist[MAXDIM], temp_seek;
int srcOff; /* Needed since LO don't understand SEEK_CUR*/
char *baseDestFp = (char *)destfp;
CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
n = ARR_NDIM(array);
dim = ARR_DIMS(array);
lb = ARR_LBOUND(array);
C = A->C;
csize = C[n-1];
PC[n-1] = 1;
temp = dim[n - 1]/C[n-1];
for (i = n-2; i >= 0; i--){
PC[i] = PC[i+1] * temp;
temp = dim[i] / C[i];
csize *= C[i];
}
for (i = 0; i < n; st[i] -= lb[i], endp[i] -= lb[i], i++)
;
mda_get_prod(n, C, PCHUNK);
mda_get_range(n, array_span, st, endp);
mda_get_prod(n, array_span, PA);
array2chunk_coord(n, C, st, chunk_st);
array2chunk_coord(n, C, endp, chunk_end);
mda_get_range(n, chunk_span, chunk_st, chunk_end);
mda_get_offset_values(n, dist, PC, chunk_span);
for (i = 0; i < n; i++) {
range_st[i] = st[i];
range_end[i] = min(chunk_st[i]*C[i]+C[i]-1, endp[i]);
}
for (i = j = 0; i < n; i++)
j+= chunk_st[i]*PC[i];
temp_seek = srcOff = j * csize * bsize;
if (lo_lseek(fp, srcOff, SEEK_SET) < 0) RETURN_NULL;
jj = n-1;
for (i = 0; i < n; chunk_off[i++] = 0)
;
words_read = 0; temp_seek = 0;
do {
/* Write chunk (chunk_st) to output buffer */
mda_get_range(n, array_span, range_st, range_end);
mda_get_offset_values(n, adist, PA, array_span);
mda_get_offset_values(n, cdist, PCHUNK, array_span);
for (i=0; i < n; range[i] = range_st[i]-st[i], i++);
bptr = tuple2linear(n, range, PA);
for (i = 0; i < n; range[i++] = 0);
j = n-1; bptr *= bsize;
if (isDestLO) {
if (lo_lseek(destfp, bptr, SEEK_SET) < 0)
RETURN_NULL;
}
else
destfp = baseDestFp + bptr;
for(i = 0, block_seek = 0; i < n; i++)
block_seek += (range_st[i]-(chunk_st[i] + chunk_off[i])
*C[i])*PCHUNK[i];
if (dist[jj] + block_seek + temp_seek) {
temp = (dist[jj]*csize+block_seek+temp_seek)*bsize;
srcOff += temp;
if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
RETURN_NULL;
}
for (i = n-1, to_read = bsize; i >= 0;
to_read *= min(C[i], array_span[i]), i--)
if (cdist[i] || adist[i])
break;
do {
if (cdist[j]) {
srcOff += (cdist[j]*bsize);
if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
RETURN_NULL;
}
block_seek += cdist[j];
bptr += adist[j]*bsize;
if (isDestLO) {
if (lo_lseek(destfp, bptr, SEEK_SET) < 0)
RETURN_NULL;
}
else
destfp = baseDestFp + bptr;
temp = _LOtransfer ((char**)&destfp, to_read, 1, (char**)&fp, 1, isDestLO);
if (temp < to_read)
RETURN_NULL;
srcOff += to_read;
words_read+=to_read;
bptr += to_read;
block_seek += (to_read/bsize);
/*
* compute next tuple in range[]
*/
{
int x;
if (!(i+1))
j = -1;
else {
range[i] = (range[i]+1)%array_span[i];
for (x = i; x*(!range[x]); x--)
range[x-1] = (range[x-1]+1)%array_span[x-1];
if (x)
j = x;
else {
if (range[0])
j = 0;
else
j = -1;
}
}
}
/*
* end of compute next tuple --
* j is set to -1 if tuple generation is over
*/
} while (j != -1);
block_seek = csize - block_seek;
temp_seek = block_seek;
jj = next_tuple(n, chunk_off, chunk_span);
if (jj == -1)
break;
range_st[jj] = (chunk_st[jj]+chunk_off[jj])*C[jj];
range_end[jj] = min(range_st[jj] + C[jj]-1, endp[jj]);
for (i = jj+1; i < n; i++) {
range_st[i] = st[i];
range_end[i] = min((chunk_st[i]+chunk_off[i])*C[i]+C[i]-1, endp[i]);
}
} while (jj != -1);
return(words_read);
}
/*------------------------------------------------------------------------
* _ReadChunkArray1El --
* returns one element of the chunked array as specified by the index "st"
* the chunked file descriptor is "fp"
*-------------------------------------------------------------------------
*/
struct varlena *
_ReadChunkArray1El(int st[],
int bsize,
int fp,
ArrayType *array,
bool *isNull)
{
int i, j, n, temp, srcOff;
int chunk_st[MAXDIM];
int *C, csize, *dim, *lb;
int PCHUNK[MAXDIM], PC[MAXDIM];
CHUNK_INFO *A = (CHUNK_INFO *) ARR_DATA_PTR(array);
n = ARR_NDIM(array);
lb = ARR_LBOUND(array);
C = A->C;
dim = ARR_DIMS(array);
csize = C[n-1];
PC[n-1] = 1;
temp = dim[n - 1]/C[n-1];
for (i = n-2; i >= 0; i--){
PC[i] = PC[i+1] * temp;
temp = dim[i] / C[i];
csize *= C[i];
}
for (i = 0; i < n; st[i] -= lb[i], i++);
mda_get_prod(n, C, PCHUNK);
array2chunk_coord(n, C, st, chunk_st);
for (i = j = 0; i < n; i++)
j+= chunk_st[i]*PC[i];
srcOff = j * csize;
for(i = 0; i < n; i++)
srcOff += (st[i]-chunk_st[i]*C[i])*PCHUNK[i];
srcOff *= bsize;
if (lo_lseek(fp, srcOff, SEEK_SET) < 0)
RETURN_NULL;
#ifdef LOARRAY
return (struct varlena *) LOread(fp, bsize);
#endif
return (struct varlena *) 0;
}

View File

@@ -0,0 +1,891 @@
/*-------------------------------------------------------------------------
*
* date.c--
* Functions for the built-in type "AbsoluteTime".
* Functions for the built-in type "RelativeTime".
* Functions for the built-in type "TimeInterval".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
* NOTES
* This code is actually (almost) unused.
* It needs to be integrated with Time and struct trange.
*
* XXX This code needs to be rewritten to work with the "new" definitions
* XXX in h/tim.h. Look for int32's, int, long, etc. in the code. The
* XXX definitions in h/tim.h may need to be rethought also.
*
* XXX This code has been cleaned up some - avi 07/07/93
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <string.h>
#include "postgres.h"
#include "miscadmin.h"
#include "access/xact.h"
#include "utils/builtins.h" /* where function declarations go */
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/nabstime.h"
#define TM_YEAR_BASE 1900 /* compatible to UNIX time */
#define EPOCH_YEAR 1970 /* compatible to UNIX time */
#define YEAR_MAX 2038 /* otherwise overflow */
#define YEAR_MIN 1902 /* otherwise overflow */
#define DAYS_PER_LYEAR 366
#define DAYS_PER_NYEAR 365
#define HOURS_PER_DAY 24
#define MINS_PER_HOUR 60
#define SECS_PER_MIN 60
#define MAX_LONG 2147483647 /* 2^31 */
/* absolute time definitions */
#define TIME_NOW_STR "now" /* represents time now */
#define TIME_EPOCH_STR "epoch" /* Jan 1 00:00:00 1970 GMT */
#define TIME_EPOCH_STR_LEN (sizeof(TIME_EPOCH_STR)-1)
#define INVALID_ABSTIME_STR "Undefined AbsTime"
#define INVALID_ABSTIME_STR_LEN (sizeof(INVALID_ABSTIME_STR)-1)
#define INVALID_RELTIME_STR "Undefined RelTime"
#define INVALID_RELTIME_STR_LEN (sizeof(INVALID_RELTIME_STR)-1)
#define RELTIME_LABEL '@'
#define RELTIME_PAST "ago"
#define DIRMAXLEN (sizeof(RELTIME_PAST)-1)
/*
* Unix epoch is Jan 1 00:00:00 1970. Postgres knows about times
* sixty-eight years on either side of that.
*/
#define IsCharDigit(C) isdigit(C)
#define IsCharA_Z(C) isalpha(C)
#define IsSpace(C) ((C) == ' ')
#define IsNull(C) ((C) == NULL)
#define T_INTERVAL_INVAL 0 /* data represents no valid interval */
#define T_INTERVAL_VALID 1 /* data represents a valid interval */
/*
* ['Mon May 10 23:59:12 1943 PST' 'Sun Jan 14 03:14:21 1973 PST']
* 0 1 2 3 4 5 6
* 1234567890123456789012345678901234567890123456789012345678901234
*
* we allocate some extra -- timezones are usually 3 characters but
* this is not in the POSIX standard...
*/
#define T_INTERVAL_LEN 80
#define INVALID_INTERVAL_STR "Undefined Range"
#define INVALID_INTERVAL_STR_LEN (sizeof(INVALID_INTERVAL_STR)-1)
#define ABSTIMEMIN(t1, t2) abstimele((t1),(t2)) ? (t1) : (t2)
#define ABSTIMEMAX(t1, t2) abstimelt((t1),(t2)) ? (t2) : (t1)
static char *month_name[] = {
"Jan","Feb","Mar","Apr","May","Jun","Jul",
"Aug","Sep","Oct","Nov","Dec" };
static char *unit_tab[] = {
"second", "seconds", "minute", "minutes",
"hour", "hours", "day", "days", "week", "weeks",
"month", "months", "year", "years"};
#define UNITMAXLEN 7 /* max length of a unit name */
#define NUNITS 14 /* number of different units */
/* table of seconds per unit (month = 30 days, year = 365 days) */
static int sec_tab[] = {
1,1, 60, 60,
3600, 3600, 86400, 86400, 604800, 604800,
2592000, 2592000, 31536000, 31536000 };
/* maximal values (in seconds) per unit which can be represented */
static int unit_max_quantity[] = {
2144448000, 2144448000, 35740800, 35740800,
595680, 595680, 24820, 24820, 3545, 3545,
827, 827, 68, 68 };
struct timeb *TimeDifferenceFromGMT = NULL;
static bool TimeDiffIsInited = false;
static char *timezonename = NULL;
/*
* Function prototypes -- internal to this file only
*/
static int correct_unit(char unit[], int *unptr);
static int correct_dir(char direction[], int *signptr);
static int istinterval(char *i_string,
AbsoluteTime *i_start,
AbsoluteTime *i_end);
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* reltimein - converts a reltime string in an internal format
*/
int32 /* RelativeTime */
reltimein(char *timestring)
{
int error;
int32 /* RelativeTime */ timeinsec;
int sign, unitnr;
long quantity;
error = isreltime(timestring, &sign, &quantity, &unitnr);
#ifdef DATEDEBUG
elog(DEBUG, "reltimein: isreltime(%s) returns error=%d, %d, %d, %d",
timestring, error, sign, quantity, unitnr);
#endif /* !DATEDEBUG */
if (error != 1) {
timeinsec = INVALID_RELTIME; /*invalid time representation */
} else {
/* this check is necessary, while no control on overflow */
if (quantity > unit_max_quantity[unitnr] || quantity < 0) {
#ifdef DATEDEBUG
elog(DEBUG, "reltimein: illegal quantity %d (< %d)",
quantity, unit_max_quantity[unitnr]);
#endif /* DATEDEBUG */
timeinsec = INVALID_RELTIME; /* illegal quantity */
} else {
timeinsec = sign * quantity * sec_tab[unitnr];
#ifdef DATEDEBUG
elog(DEBUG, "reltimein: computed timeinsec %d",
timeinsec);
#endif /* DATEDEBUG */
}
}
return(timeinsec);
}
/*
* reltimeout - converts the internal format to a reltime string
*/
char *reltimeout(int32 timevalue)
{
char *timestring;
long quantity;
register int i;
int unitnr;
timestring = (char *) palloc(Max(strlen(INVALID_RELTIME_STR),
UNITMAXLEN) + 1);
if (timevalue == INVALID_RELTIME) {
(void) strcpy(timestring,INVALID_RELTIME_STR);
return(timestring);
}
if (timevalue == 0)
i = 1; /* unit = 'seconds' */
else
for (i = 12; i >= 0; i = i-2)
if ((timevalue % sec_tab[i]) == 0)
break; /* appropriate unit found */
unitnr = i;
quantity = (timevalue / sec_tab[unitnr]);
if (quantity > 1 || quantity < -1)
unitnr++; /* adjust index for PLURAL of unit */
if (quantity >= 0)
(void) sprintf( timestring, "%c %lu %s", RELTIME_LABEL,
quantity, unit_tab[unitnr]);
else
(void) sprintf( timestring, "%c %lu %s %s", RELTIME_LABEL,
(quantity * -1), unit_tab[unitnr], RELTIME_PAST);
return(timestring);
}
/*
* tintervalin - converts an interval string to an internal format
*/
TimeInterval tintervalin(char *intervalstr)
{
int error;
AbsoluteTime i_start, i_end, t1, t2;
TimeInterval interval;
interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
error = istinterval(intervalstr, &t1, &t2);
if (error == 0)
interval->status = T_INTERVAL_INVAL;
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
interval->status = T_INTERVAL_INVAL; /* undefined */
else {
i_start = ABSTIMEMIN(t1, t2);
i_end = ABSTIMEMAX(t1, t2);
interval->data[0] = i_start;
interval->data[1] = i_end;
interval->status = T_INTERVAL_VALID;
}
return(interval);
}
/*
* tintervalout - converts an internal interval format to a string
*
*/
char *tintervalout(TimeInterval interval)
{
char *i_str, *p;
i_str = (char *) palloc( T_INTERVAL_LEN ); /* ['...' '...'] */
(void) strcpy(i_str,"['");
if (interval->status == T_INTERVAL_INVAL)
(void) strcat(i_str,INVALID_INTERVAL_STR);
else {
p = nabstimeout(interval->data[0]);
(void) strcat(i_str,p);
pfree(p);
(void) strcat(i_str,"' '");
p = nabstimeout(interval->data[1]);
(void) strcat(i_str,p);
pfree(p);
}
(void) strcat(i_str,"']\0");
return(i_str);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
/*
* mktinterval - creates a time interval with endpoints t1 and t2
*/
TimeInterval mktinterval(AbsoluteTime t1, AbsoluteTime t2)
{
AbsoluteTime tstart = ABSTIMEMIN(t1, t2), tend = ABSTIMEMAX(t1, t2);
TimeInterval interval;
interval = (TimeInterval) palloc(sizeof(TimeIntervalData));
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
interval->status = T_INTERVAL_INVAL;
else {
interval->status = T_INTERVAL_VALID;
interval->data[0] = tstart;
interval->data[1] = tend;
}
return interval;
}
/*
* timepl, timemi and abstimemi use the formula
* abstime + reltime = abstime
* so abstime - reltime = abstime
* and abstime - abstime = reltime
*/
/*
* timepl - returns the value of (abstime t1 + relime t2)
*/
AbsoluteTime timepl(AbsoluteTime t1, RelativeTime t2)
{
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (AbsoluteTimeIsReal(t1) &&
RelativeTimeIsValid(t2) &&
((t2 > 0) ? (t1 < NOEND_ABSTIME - t2)
: (t1 > NOSTART_ABSTIME - t2))) /* prevent overflow */
return (t1 + t2);
return(INVALID_ABSTIME);
}
/*
* timemi - returns the value of (abstime t1 - reltime t2)
*/
AbsoluteTime timemi(AbsoluteTime t1, RelativeTime t2)
{
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (AbsoluteTimeIsReal(t1) &&
RelativeTimeIsValid(t2) &&
((t2 > 0) ? (t1 > NOSTART_ABSTIME + t2)
: (t1 < NOEND_ABSTIME + t2))) /* prevent overflow */
return (t1 - t2);
return(INVALID_ABSTIME);
}
/*
* abstimemi - returns the value of (abstime t1 - abstime t2)
*/
static RelativeTime abstimemi(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
if (AbsoluteTimeIsReal(t1) &&
AbsoluteTimeIsReal(t2))
return (t1 - t2);
return(INVALID_RELTIME);
}
/*
* ininterval - returns 1, iff absolute date is in the interval
*/
int ininterval(AbsoluteTime t, TimeInterval interval)
{
if (interval->status == T_INTERVAL_VALID && t != INVALID_ABSTIME)
return (abstimege(t, interval->data[0]) &&
abstimele(t, interval->data[1]));
return(0);
}
/*
* intervalrel - returns relative time corresponding to interval
*/
RelativeTime intervalrel(TimeInterval interval)
{
if (interval->status == T_INTERVAL_VALID)
return(abstimemi(interval->data[1], interval->data[0]));
else
return(INVALID_RELTIME);
}
/*
* timenow - returns time "now", internal format
*
* Now AbsoluteTime is time since Jan 1 1970 -mer 7 Feb 1992
*/
AbsoluteTime timenow()
{
time_t sec;
if (time(&sec) < 0)
return(INVALID_ABSTIME);
return((AbsoluteTime) sec);
}
/*
* reltimeeq - returns 1, iff arguments are equal
* reltimene - returns 1, iff arguments are not equal
* reltimelt - returns 1, iff t1 less than t2
* reltimegt - returns 1, iff t1 greater than t2
* reltimele - returns 1, iff t1 less than or equal to t2
* reltimege - returns 1, iff t1 greater than or equal to t2
*/
int32 reltimeeq(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 == t2);
}
int32 reltimene(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 != t2);
}
int32 reltimelt(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 < t2);
}
int32 reltimegt(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 > t2);
}
int32 reltimele(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 <= t2);
}
int32 reltimege(RelativeTime t1, RelativeTime t2)
{
if (t1 == INVALID_RELTIME || t2 == INVALID_RELTIME)
return 0;
return(t1 >= t2);
}
/*
* intervaleq - returns 1, iff interval i1 is equal to interval i2
*/
int32 intervaleq(TimeInterval i1, TimeInterval i2)
{
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
return(0); /* invalid interval */
return(abstimeeq(i1->data[0], i2->data[0]) &&
abstimeeq(i1->data[1], i2->data[1]));
}
/*
* intervalleneq - returns 1, iff length of interval i is equal to
* reltime t
*/
int32 intervalleneq(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt == t);
}
/*
* intervallenne - returns 1, iff length of interval i is not equal
* to reltime t
*/
int32 intervallenne(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt != t);
}
/*
* intervallenlt - returns 1, iff length of interval i is less than
* reltime t
*/
int32 intervallenlt(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt < t);
}
/*
* intervallengt - returns 1, iff length of interval i is greater than
* reltime t
*/
int32 intervallengt(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt > t);
}
/*
* intervallenle - returns 1, iff length of interval i is less or equal
* than reltime t
*/
int32 intervallenle(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt <= t);
}
/*
* intervallenge - returns 1, iff length of interval i is greater or
* equal than reltime t
*/
int32 intervallenge(TimeInterval i, RelativeTime t)
{
RelativeTime rt;
if ((i->status == T_INTERVAL_INVAL) || (t == INVALID_RELTIME))
return(0);
rt = intervalrel(i);
return (rt != INVALID_RELTIME && rt >= t);
}
/*
* intervalct - returns 1, iff interval i1 contains interval i2
*/
int32 intervalct(TimeInterval i1, TimeInterval i2)
{
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
return(0);
return(abstimele(i1->data[0], i2->data[0]) &&
abstimege(i1->data[1], i2->data[1]));
}
/*
* intervalov - returns 1, iff interval i1 (partially) overlaps i2
*/
int32 intervalov(TimeInterval i1, TimeInterval i2)
{
if (i1->status == T_INTERVAL_INVAL || i2->status == T_INTERVAL_INVAL)
return(0);
return(! (abstimelt(i1->data[1], i2->data[0]) ||
abstimegt(i1->data[0], i2->data[1])));
}
/*
* intervalstart - returns the start of interval i
*/
AbsoluteTime intervalstart(TimeInterval i)
{
if (i->status == T_INTERVAL_INVAL)
return INVALID_ABSTIME;
return(i->data[0]);
}
/*
* intervalend - returns the end of interval i
*/
AbsoluteTime intervalend(TimeInterval i)
{
if (i->status == T_INTERVAL_INVAL)
return INVALID_ABSTIME;
return(i->data[1]);
}
/*****************************************************************************
* PRIVATE ROUTINES *
*****************************************************************************/
/*
* isreltime - returns 1, iff datestring is of type reltime
* 2, iff datestring is 'invalid time' identifier
* 0, iff datestring contains a syntax error
*
* output parameter:
* sign = -1, iff direction is 'ago'
* else sign = 1.
* quantity : quantity of unit
* unitnr : 0 or 1 ... sec
* 2 or 3 ... min
* 4 or 5 ... hour
* 6 or 7 ... day
* 8 or 9 ... week
* 10 or 11... month
* 12 or 13... year
*
*
* Relative time:
*
* `@' ` ' Quantity ` ' Unit [ ` ' Direction]
*
* OR `Undefined RelTime' (see also INVALID_RELTIME_STR)
*
* where
* Quantity is `1', `2', ...
* Unit is `second', `minute', `hour', `day', `week',
* `month' (30-days), or `year' (365-days),
* or PLURAL of these units.
* Direction is `ago'
*
* VALID time less or equal `@ 68 years'
*
*/
int isreltime(char *timestring, int *sign, long *quantity, int *unitnr)
{
register char *p;
register char c;
int i;
char unit[UNITMAXLEN] ;
char direction[DIRMAXLEN];
int localSign;
int localUnitNumber;
long localQuantity;
if (!PointerIsValid(sign)) {
sign = &localSign;
}
if (!PointerIsValid(unitnr)) {
unitnr = &localUnitNumber;
}
if (!PointerIsValid(quantity)) {
quantity = &localQuantity;
}
unit[0] = '\0';
direction[0] = '\0';
p = timestring;
/* skip leading blanks */
while ((c = *p) != '\0') {
if (c != ' ')
break;
p++;
}
/* Test whether 'invalid time' identifier or not */
if (!strncmp(INVALID_RELTIME_STR,p,strlen(INVALID_RELTIME_STR) + 1))
return(2); /* correct 'invalid time' identifier found */
/* handle label of relative time */
if (c != RELTIME_LABEL)
return(0); /*syntax error*/
c = *++p;
if (c != ' ') return(0); /*syntax error*/
p++;
/* handle the quantity */
*quantity = 0;
for (;;) {
c = *p;
if (isdigit(c)) {
*quantity = *quantity * 10 + (c -'0');
p++;
} else {
if (c == ' ' )
break; /* correct quantity found */
else
return(0); /* syntax error */
}
}
/* handle unit */
p++;
i = 0;
for (;;) {
c = *p;
if (c >= 'a' && c <= 'z' && i <= (UNITMAXLEN - 1)) {
unit[i] = c;
p++;
i++;
} else {
if ((c == ' ' || c == '\0')
&& correct_unit(unit, unitnr))
break; /* correct unit found */
else
return(0); /* syntax error */
}
}
/* handle optional direction */
if (c == ' ')
p++;
i = 0;
*sign = 1;
for (;;) {
c = *p;
if (c >= 'a' && c <= 'z' && i <= (DIRMAXLEN - 1)) {
direction[i] = c;
p++;
i++;
} else {
if ((c == ' ' || c == '\0') && i == 0) {
*sign = 1;
break; /* no direction specified */
}
if ((c == ' ' || c == '\0') && i != 0)
{
direction[i] = '\0';
correct_dir(direction, sign);
break; /* correct direction found */
}
else
return(0); /* syntax error*/
}
}
return(1);
}
/*
* correct_unit - returns 1, iff unit is a correct unit description
*
* output parameter:
* unptr: points to an integer which is the appropriate unit number
* (see function isreltime())
*/
static int correct_unit(char unit[], int *unptr)
{
int j = 0;
while (j < NUNITS) {
if (strncmp(unit, unit_tab[j], strlen(unit_tab[j])) == 0) {
*unptr = j;
return(1);
}
j++;
}
return (0); /* invalid unit descriptor */
}
/*
* correct_dir - returns 1, iff direction is a correct identifier
*
* output parameter:
* signptr: points to -1 if dir corresponds to past tense
* else to 1
*/
static int correct_dir(char direction[], int *signptr)
{
*signptr = 1;
if (strncmp(RELTIME_PAST, direction, strlen(RELTIME_PAST)+1) == 0)
{
*signptr = -1;
return(1);
} else
return (0); /* invalid direction descriptor */
}
/*
* istinterval - returns 1, iff i_string is a valid interval descr.
* 0, iff i_string is NOT a valid interval desc.
* 2, iff any time is INVALID_ABSTIME
*
* output parameter:
* i_start, i_end: interval margins
*
* Time interval:
* `[' {` '} `'' <AbsTime> `'' {` '} `'' <AbsTime> `'' {` '} `]'
*
* OR `Undefined Range' (see also INVALID_INTERVAL_STR)
*
* where <AbsTime> satisfies the syntax of absolute time.
*
* e.g. [ ' Jan 18 1902' 'Jan 1 00:00:00 1970']
*/
static int istinterval(char *i_string,
AbsoluteTime *i_start,
AbsoluteTime *i_end)
{
register char *p,*p1;
register char c;
p = i_string;
/* skip leading blanks up to '[' */
while ((c = *p) != '\0') {
if ( IsSpace(c))
p++;
else if (c != '[')
return(0); /* syntax error */
else
break;
}
p++;
/* skip leading blanks up to "'" */
while ((c = *p) != '\0') {
if (IsSpace(c))
p++;
else if (c != '"')
return (0); /* syntax error */
else
break;
}
p++;
if (strncmp(INVALID_INTERVAL_STR,p,strlen(INVALID_INTERVAL_STR)) == 0)
return(0); /* undefined range, handled like a syntax err.*/
/* search for the end of the first date and change it to a NULL*/
p1 = p;
while ((c = *p1) != '\0') {
if ( c == '"') {
*p1 = '\0';
break;
}
p1++;
}
/* get the first date */
*i_start = nabstimein(p); /* first absolute date */
/* rechange NULL at the end of the first date to a "'" */
*p1 = '"';
p = ++p1;
/* skip blanks up to "'", beginning of second date*/
while ((c = *p) != '\0') {
if (IsSpace(c))
p++;
else if (c != '"')
return (0); /* syntax error */
else
break;
}
p++;
/* search for the end of the second date and change it to a NULL*/
p1 = p;
while ((c = *p1) != '\0') {
if ( c == '"') {
*p1 = '\0';
break;
}
p1++;
}
/* get the second date */
*i_end = nabstimein(p); /* second absolute date */
/* rechange NULL at the end of the first date to a ''' */
*p1 = '"';
p = ++p1;
/* skip blanks up to ']'*/
while ((c = *p) != '\0') {
if ( IsSpace(c))
p++;
else if (c != ']')
return(0); /*syntax error */
else
break;
}
p++;
c = *p;
if ( c != '\0' )
return (0); /* syntax error */
/* it seems to be a valid interval */
return(1);
}
/*****************************************************************************
*
*****************************************************************************/
/*
* timeofday -
* returns the current time as a text. similar to timenow() but returns
* seconds with more precision (up to microsecs). (I need this to compare
* the Wisconsin benchmark with Illustra whose TimeNow() shows current
* time with precision up to microsecs.) - ay 3/95
*/
text *
timeofday()
{
#ifndef WIN32
struct timeval tp;
struct timezone tpz;
#endif /* WIN32 */
char templ[500];
char buf[500];
text *tm;
int len = 0;
#ifndef WIN32
gettimeofday(&tp, &tpz);
(void) strftime(templ, sizeof(templ), "%a %b %d %H:%M:%S.%%d %Y %Z",
localtime((time_t *) &tp.tv_sec));
sprintf(buf, templ, tp.tv_usec);
len = VARHDRSZ + strlen(buf);
tm = (text *)palloc(len);
VARSIZE(tm) = len;
strncpy(VARDATA(tm), buf, strlen(buf));
return tm;
#else
len = len / len;
return tm;
#endif /* WIN32 */
}

View File

@@ -0,0 +1,350 @@
/*-------------------------------------------------------------------------
*
* datetimes.c--
* implements DATE and TIME data types specified in SQL-92 standard
*
* Copyright (c) 1994-5, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/datetimes.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/elog.h"
/* these things look like structs, but we pass them by value so be careful
For example, passing an int -> DateADT is not portable! */
typedef struct DateADT {
char day;
char month;
short year;
} DateADT;
typedef struct TimeADT {
short hr;
short min;
float sec;
} TimeADT;
#ifndef EUROPEAN_STYLE
#define AMERICAN_STYLE
#endif
static int day_tab[2][12] = {
{31,28,31,30,31,30,31,31,30,31,30,31},
{31,29,31,30,31,30,31,31,30,31,30,31} };
static int
isleap(int year)
{
return
(((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0);
}
/*****************************************************************************
* Date ADT
*****************************************************************************/
int4
date_in(char *datestr)
{
int d, m, y;
int4 result;
DateADT *date = (DateADT*)&result;
#ifdef USE_SHORT_YEAR
#define CHECK_DATE_LEN(datestr) (strlen(datestr) >= 8)
#else
#define CHECK_DATE_LEN(datestr) (strlen(datestr) == 10)
#endif /* USE_SHORT_YEAR */
#ifdef AMERICAN_STYLE
if (!CHECK_DATE_LEN(datestr) ||
sscanf(datestr, "%d%*c%d%*c%d", &m, &d, &y) != 3) {
elog(WARN, "date_in: date \"%s\" not of the form mm-dd-yyyy",
datestr);
}
#else
if (!CHECK_DATE_LEN(datestr) ||
sscanf(datestr, "%d%*c%d%*c%d", &d, &m, &y) != 3) {
elog(WARN, "date_in: date \"%s\" not of the form dd-mm-yyyy",
datestr);
}
#endif
if (m < 1 || m > 12)
elog(WARN, "date_in: month must be limited to values 1 through 12 in \"%s\"", datestr);
if (d < 1 || d > day_tab[isleap(y)][m-1])
elog(WARN, "date_in: day must be limited to values 1 through %d in \"%s\"",
day_tab[isleap(y)][m-1], datestr);
#ifdef USE_SHORT_YEAR
if (y < 100)
y += 1900; /* hack! */
#endif /* USE_SHORT_YEAR */
date->day = d;
date->month = m;
date->year = y;
return result;
}
char *
date_out(int4 dateVal)
{
char *datestr = palloc(11);
int4 dateStore;
DateADT *date;
/* DateADT is a structure that happens to be four bytes long,
trust me on this.... */
date = (DateADT*)&dateStore;
dateStore = dateVal;
#ifdef AMERICAN_STYLE
sprintf(datestr, "%02d-%02d-%04d",
(int)date->month, (int)date->day, (int)date->year);
#else
sprintf(datestr, "%02d-%02d-%04d",
(int)date->day, (int)date->month, (int)date->year);
#endif
return datestr;
}
int
date_eq(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
return (date1->day==date2->day &&
date1->month==date2->month &&
date1->year==date2->year);
}
int
date_ne(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
return (date1->day!=date2->day || date1->month!=date2->month ||
date1->year!=date2->year);
}
int
date_lt(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
if (date1->year!=date2->year)
return (date1->year<date2->year);
if (date1->month!=date2->month)
return (date1->month<date2->month);
return (date1->day<date2->day);
}
int
date_le(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
if (date1->year!=date2->year)
return (date1->year<=date2->year);
if (date1->month!=date2->month)
return (date1->month<=date2->month);
return (date1->day<=date2->day);
}
int
date_gt(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
if (date1->year!=date2->year)
return (date1->year>date2->year);
if (date1->month!=date2->month)
return (date1->month>date2->month);
return (date1->day>date2->day);
}
int
date_ge(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
if (date1->year!=date2->year)
return (date1->year>=date2->year);
if (date1->month!=date2->month)
return (date1->month>=date2->month);
return (date1->day>=date2->day);
}
int
date_cmp(int4 dateVal1, int4 dateVal2)
{
int4 dateStore1 = dateVal1;
int4 dateStore2 = dateVal2;
DateADT *date1, *date2;
date1 = (DateADT*)&dateStore1;
date2 = (DateADT*)&dateStore2;
if (date1->year!=date2->year)
return ((date1->year<date2->year) ? -1 : 1);
if (date1->month!=date2->month)
return ((date1->month<date2->month) ? -1 : 1);
if (date1->day!=date2->day)
return ((date1->day<date2->day) ? -1 : 1);
return 0;
}
/*****************************************************************************
* Time ADT
*****************************************************************************/
char *
time_in(char *timestr)
{
int h, m;
float sec;
TimeADT *time;
if (sscanf(timestr, "%d%*c%d%*c%f", &h, &m, &sec) != 3) {
elog(WARN, "time_in: time \"%s\" not of the form hh:mm:ss",
timestr);
}
if (h < 0 || h > 23)
elog(WARN, "time_in: hour must be limited to values 0 through 23 in \"%s\"", timestr);
if (m < 0 || m > 59)
elog(WARN, "time_in: minute must be limited to values 0 through 59 in \"%s\"", timestr);
if (sec < 0 || sec >= 62.0)
elog(WARN, "time_in: second must be limited to values 0 through 61.99 in \"%s\"", timestr);
time = (TimeADT*)palloc(sizeof(TimeADT));
time->hr = h;
time->min = m;
time->sec = sec;
return (char*)time;
}
char *
time_out(TimeADT *time)
{
char *timestr = palloc(16);
sprintf(timestr, "%02d:%02d:%09.6f",
(int)time->hr, (int)time->min, time->sec);
return timestr;
}
int
time_eq(TimeADT *time1, TimeADT *time2)
{
return (time1->sec==time2->sec && time1->min==time2->min &&
time1->hr==time2->hr);
}
int
time_ne(TimeADT *time1, TimeADT *time2)
{
return (time1->sec!=time2->sec || time1->min!=time2->min ||
time1->hr!=time2->hr);
}
int
time_lt(TimeADT *time1, TimeADT *time2)
{
if (time1->hr!=time2->hr)
return (time1->hr<time2->hr);
if (time1->min!=time2->min)
return (time1->min<time2->min);
return (time1->sec<time2->sec);
}
int
time_le(TimeADT *time1, TimeADT *time2)
{
if (time1->hr!=time2->hr)
return (time1->hr<=time2->hr);
if (time1->min!=time2->min)
return (time1->min<=time2->min);
return (time1->sec<=time2->sec);
}
int
time_gt(TimeADT *time1, TimeADT *time2)
{
if (time1->hr!=time2->hr)
return (time1->hr>time2->hr);
if (time1->min!=time2->min)
return (time1->min>time2->min);
return (time1->sec>time2->sec);
}
int
time_ge(TimeADT *time1, TimeADT *time2)
{
if (time1->hr!=time2->hr)
return (time1->hr>=time2->hr);
if (time1->min!=time2->min)
return (time1->min>=time2->min);
return (time1->sec>=time2->sec);
}
int
time_cmp(TimeADT *time1, TimeADT *time2)
{
if (time1->hr!=time2->hr)
return ((time1->hr<time2->hr) ? -1 : 1);
if (time1->min!=time2->min)
return ((time1->min<time2->min) ? -1 : 1);
if (time1->sec!=time2->sec)
return ((time1->sec<time2->sec) ? -1 : 1);
return 0;
}
int32 /* RelativeTime */
int42reltime(int32 timevalue)
{
return(timevalue);
}

View File

@@ -0,0 +1,201 @@
/*-------------------------------------------------------------------------
*
* datum.c--
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/datum.c,v 1.1.1.1 1996/07/09 06:22:03 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* In the implementation of the next routines we assume the following:
*
* A) if a type is "byVal" then all the information is stored in the
* Datum itself (i.e. no pointers involved!). In this case the
* length of the type is always greater than zero and less than
* "sizeof(Datum)"
* B) if a type is not "byVal" and it has a fixed length, then
* the "Datum" always contain a pointer to a stream of bytes.
* The number of significant bytes are always equal to the length of the
* type.
* C) if a type is not "byVal" and is of variable length (i.e. it has
* length == -1) then "Datum" always points to a "struct varlena".
* This varlena structure has information about the actual length of this
* particular instance of the type and about its value.
*
*/
#include <string.h>
#include "postgres.h"
#include "utils/datum.h"
#include "catalog/pg_type.h"
#include "utils/elog.h"
#include "utils/palloc.h"
/*-------------------------------------------------------------------------
* datumGetSize
*
* Find the "real" size of a datum, given the datum value,
* its type, whether it is a "by value", and its length.
*
* To cut a long story short, usually the real size is equal to the
* type length, with the exception of variable length types which have
* a length equal to -1. In this case, we have to look at the value of
* the datum itself (which is a pointer to a 'varlena' struct) to find
* its size.
*-------------------------------------------------------------------------
*/
Size
datumGetSize(Datum value, Oid type, bool byVal, Size len)
{
struct varlena *s;
Size size;
if (byVal) {
if (len >= 0 && len <= sizeof(Datum)) {
size = len;
} else {
elog(WARN,
"datumGetSize: Error: type=%ld, byVaL with len=%d",
(long) type, len);
}
} else { /* not byValue */
if (len == -1) {
/*
* variable length type
* Look at the varlena struct for its real length...
*/
s = (struct varlena *) DatumGetPointer(value);
if (!PointerIsValid(s)) {
elog(WARN,
"datumGetSize: Invalid Datum Pointer");
}
size = (Size) VARSIZE(s);
} else {
/*
* fixed length type
*/
size = len;
}
}
return(size);
}
/*-------------------------------------------------------------------------
* datumCopy
*
* make a copy of a datum
*
* If the type of the datum is not passed by value (i.e. "byVal=false")
* then we assume that the datum contains a pointer and we copy all the
* bytes pointed by this pointer
*-------------------------------------------------------------------------
*/
Datum
datumCopy(Datum value, Oid type, bool byVal, Size len)
{
Size realSize;
Datum res;
char *s;
if (byVal) {
res = value;
} else {
if (value == 0) return((Datum)NULL);
realSize = datumGetSize(value, type, byVal, len);
/*
* the value is a pointer. Allocate enough space
* and copy the pointed data.
*/
s = (char *) palloc(realSize);
if (s == NULL) {
elog(WARN,"datumCopy: out of memory\n");
}
memmove(s, DatumGetPointer(value), realSize);
res = (Datum)s;
}
return(res);
}
/*-------------------------------------------------------------------------
* datumFree
*
* Free the space occupied by a datum CREATED BY "datumCopy"
*
* NOTE: DO NOT USE THIS ROUTINE with datums returned by amgetattr() etc.
* ONLY datums created by "datumCopy" can be freed!
*-------------------------------------------------------------------------
*/
void
datumFree(Datum value, Oid type, bool byVal, Size len)
{
Size realSize;
Pointer s;
realSize = datumGetSize(value, type, byVal, len);
if (!byVal) {
/*
* free the space palloced by "datumCopy()"
*/
s = DatumGetPointer(value);
pfree(s);
}
}
/*-------------------------------------------------------------------------
* datumIsEqual
*
* Return true if two datums are equal, false otherwise
*
* NOTE: XXX!
* We just compare the bytes of the two values, one by one.
* This routine will return false if there are 2 different
* representations of the same value (something along the lines
* of say the representation of zero in one's complement arithmetic).
*
*-------------------------------------------------------------------------
*/
bool
datumIsEqual(Datum value1, Datum value2, Oid type, bool byVal, Size len)
{
Size size1, size2;
char *s1, *s2;
if (byVal) {
/*
* just compare the two datums.
* NOTE: just comparing "len" bytes will not do the
* work, because we do not know how these bytes
* are aligned inside the "Datum".
*/
if (value1 == value2)
return(true);
else
return(false);
} else {
/*
* byVal = false
* Compare the bytes pointed by the pointers stored in the
* datums.
*/
size1 = datumGetSize(value1, type, byVal, len);
size2 = datumGetSize(value2, type, byVal, len);
if (size1 != size2)
return(false);
s1 = (char *) DatumGetPointer(value1);
s2 = (char *) DatumGetPointer(value2);
if (!memcmp(s1, s2, size1))
return(true);
else
return(false);
}
}

View File

@@ -0,0 +1,58 @@
/*-------------------------------------------------------------------------
*
* dt.c--
* Functions for the built-in type "dt".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/dt.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "c.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where function declarations go */
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* dtin - converts "nseconds" to internal representation
*
* XXX Currently, just creates an integer.
*/
int32 dtin(char *datetime)
{
if (datetime == NULL)
return((int32) 0);
return((int32) atol(datetime));
}
/*
* dtout - converts internal form to "..."
*
* XXX assumes sign, 10 digits max, '\0'
*/
char *dtout(int32 datetime)
{
char *result;
result = (char *) palloc(12);
Assert(result);
ltoa(datetime, result);
return(result);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
/* (see int.c for comparison/operation routines) */
/*****************************************************************************
* PRIVATE ROUTINES *
*****************************************************************************/
/* (none) */

View File

@@ -0,0 +1,120 @@
/*-------------------------------------------------------------------------
*
* filename.c--
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/filename.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include <stdio.h>
#ifndef WIN32
#include <pwd.h>
#endif /* WIN32 */
#include <sys/param.h>
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where function declarations go */
char *
filename_in(char *file)
{
char *str, *getenv();
int ind;
/*
* XXX - HACK CITY --- REDO
* should let the shell do expansions (shexpand)
*/
#ifndef WIN32
str = (char *) palloc(MAXPATHLEN * sizeof(*str));
str[0] = '\0';
if (file[0] == '~') {
if (file[1] == '\0' || file[1] == '/') {
/* Home directory */
char *userName;
struct passwd *pw;
userName = GetPgUserName();
if ((pw = getpwnam(userName)) == NULL) {
elog(WARN, "User %s is not a Unix user on the db server.",
userName);
}
strcpy(str, pw->pw_dir);
ind = 1;
} else {
/* Someone else's directory */
char name[16], *p;
struct passwd *pw;
int len;
if ((p = (char *) strchr(file, '/')) == NULL) {
strcpy(name, file+1);
len = strlen(name);
} else {
len = (p - file) - 1;
strncpy(name, file+1, len);
name[len] = '\0';
}
/*printf("name: %s\n");*/
if ((pw = getpwnam(name)) == NULL) {
elog(WARN, "No such user: %s\n", name);
ind = 0;
} else {
strcpy(str, pw->pw_dir);
ind = len + 1;
}
}
} else if (file[0] == '$') { /* $POSTGRESHOME, etc. expand it. */
char environment[80], *envirp, *p;
int len;
if ((p = (char *) strchr(file, '/')) == NULL) {
strcpy(environment, file+1);
len = strlen(environment);
} else {
len = (p - file) - 1;
strncpy(environment, file+1, len);
environment[len] = '\0';
}
envirp = getenv(environment);
if (envirp) {
strcpy(str, envirp);
ind = len + 1;
}
else {
elog(WARN,"Couldn't find %s in your environment", environment);
}
} else {
ind = 0;
}
strcat(str, file+ind);
return(str);
#else
return(NULL);
#endif /* WIN32 */
}
char *
filename_out(char *s)
{
char *ret;
if (!s)
return((char *) NULL);
ret = (char *) palloc(strlen(s) + 1);
if (!ret)
elog(WARN, "filename_out: palloc failed");
return(strcpy(ret, s));
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,124 @@
/*-------------------------------------------------------------------------
*
* geo-selfuncs.c--
* Selectivity routines registered in the operator catalog in the
* "oprrest" and "oprjoin" attributes.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/geo-selfuncs.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
* XXX These are totally bogus.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/attnum.h"
#include "utils/geo-decls.h" /* where function declarations go */
#include "utils/palloc.h"
float64
areasel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 4.0;
return(result);
}
float64
areajoinsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 4.0;
return(result);
}
/*
* Selectivity functions for rtrees. These are bogus -- unless we know
* the actual key distribution in the index, we can't make a good prediction
* of the selectivity of these operators.
*
* In general, rtrees need to search multiple subtrees in order to guarantee
* that all occurrences of the same key have been found. Because of this,
* the heuristic selectivity functions we return are higher than they would
* otherwise be.
*/
/*
* left_sel -- How likely is a box to be strictly left of (right of, above,
* below) a given box?
*/
float64
leftsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 6.0;
return(result);
}
float64
leftjoinsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 6.0;
return(result);
}
/*
* contsel -- How likely is a box to contain (be contained by) a given box?
*/
float64
contsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 10.0;
return(result);
}
float64
contjoinsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 10.0;
return(result);
}

343
src/backend/utils/adt/int.c Normal file
View File

@@ -0,0 +1,343 @@
/*-------------------------------------------------------------------------
*
* int.c--
* Functions for the built-in integer types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/int.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
* OLD COMMENTS
* I/O routines:
* int2in, int2out, int28in, int28out, int4in, int4out
* Conversion routines:
* itoi
* Boolean operators:
* inteq, intne, intlt, intle, intgt, intge
* Arithmetic operators:
* intpl, intmi, int4mul, intdiv
*
* Arithmetic operators:
* intmod, int4fac
*
* XXX makes massive and possibly unwarranted type promotion assumptions.
* fix me when we figure out what we want to do about ANSIfication...
*/
#include "postgres.h"
#include "fmgr.h"
#include "utils/builtins.h" /* where the declarations go */
#include "utils/elog.h"
#include "utils/palloc.h"
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* int2in - converts "num" to short
*/
int32 int2in(char *num)
{
return((int32) pg_atoi(num, sizeof(int16), '\0'));
}
/*
* int2out - converts short to "num"
*/
char *int2out(int16 sh)
{
char *result;
result = (char *)palloc(7); /* assumes sign, 5 digits, '\0' */
itoa((int) sh, result);
return(result);
}
/*
* int28in - converts "num num ..." to internal form
*
* Note:
* Fills any nonexistent digits with NULLs.
*/
int16 *int28in(char *shs)
{
register int16 (*result)[];
int nums;
if (shs == NULL)
return(NULL);
result = (int16 (*)[]) palloc(sizeof(int16 [8]));
if ((nums = sscanf(shs, "%hd%hd%hd%hd%hd%hd%hd%hd",
*result,
*result + 1,
*result + 2,
*result + 3,
*result + 4,
*result + 5,
*result + 6,
*result + 7)) != 8) {
do
(*result)[nums++] = 0;
while (nums < 8);
}
return((int16 *) result);
}
/*
* int28out - converts internal form to "num num ..."
*/
char *int28out(int16 (*shs)[])
{
register int num;
register int16 *sp;
register char *rp;
char *result;
if (shs == NULL) {
result = (char *)palloc(2);
result[0] = '-';
result[1] = '\0';
return(result);
}
rp = result = (char *)palloc(8 * 7); /* assumes sign, 5 digits, ' ' */
sp = *shs;
for (num = 8; num != 0; num--) {
itoa(*sp++, rp);
while (*++rp != '\0')
;
*rp++ = ' ';
}
*--rp = '\0';
return(result);
}
/*
* int28in - converts "num num ..." to internal form
*
* Note:
* Fills any nonexistent digits with NULLs.
*/
int32 *int44in(char *input_string)
{
int32 *foo = (int32 *)palloc(4*sizeof(int32));
register int i = 0;
i = sscanf(input_string,
"%d, %d, %d, %d",
&foo[0],
&foo[1],
&foo[2],
&foo[3]);
while (i < 4)
foo[i++] = 0;
return(foo);
}
/*
* int28out - converts internal form to "num num ..."
*/
char *int44out(int32 an_array[])
{
int temp = 4;
char *output_string = NULL;
int i;
if ( temp > 0 ) {
char *walk;
output_string = (char *)palloc(16*temp); /* assume 15 digits + sign */
walk = output_string;
for ( i = 0 ; i < temp ; i++ ) {
itoa(an_array[i],walk);
while (*++walk != '\0')
;
*walk++ = ' ';
}
*--walk = '\0';
}
return(output_string);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
/*
* int4in - converts "num" to int4
*/
int32 int4in(char *num)
{
return(pg_atoi(num, sizeof(int32), '\0'));
}
/*
* int4out - converts int4 to "num"
*/
char *int4out(int32 l)
{
char *result;
result = (char *)palloc(12); /* assumes sign, 10 digits, '\0' */
ltoa(l, result);
return(result);
}
/*
* ===================
* CONVERSION ROUTINES
* ===================
*/
int32 i2toi4(int16 arg1)
{
return((int32) arg1);
}
int16 i4toi2(int32 arg1)
{
if (arg1< -0x8000)
elog(NOTICE, "i4toi2: \"%d\" causes int2 underflow", arg1);
if (arg1 > 0x7FFF)
elog(NOTICE, "i4toi2: \"%d\" causes int2 overflow", arg1);
return((int16) arg1);
}
/*
* =========================
* BOOLEAN OPERATOR ROUTINES
* =========================
*/
/*
* inteq - returns 1 iff arg1 == arg2
* intne - returns 1 iff arg1 != arg2
* intlt - returns 1 iff arg1 < arg2
* intle - returns 1 iff arg1 <= arg2
* intgt - returns 1 iff arg1 > arg2
* intge - returns 1 iff arg1 >= arg2
*/
int32 int4eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
int32 int4ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
int32 int4lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
int32 int4le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
int32 int4gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
int32 int4ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
int32 int2eq(int16 arg1, int16 arg2) { return(arg1 == arg2); }
int32 int2ne(int16 arg1, int16 arg2) { return(arg1 != arg2); }
int32 int2lt(int16 arg1, int16 arg2) { return(arg1 < arg2); }
int32 int2le(int16 arg1, int16 arg2) { return(arg1 <= arg2); }
int32 int2gt(int16 arg1, int16 arg2) { return(arg1 > arg2); }
int32 int2ge(int16 arg1, int16 arg2) { return(arg1 >= arg2); }
int32 int24eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
int32 int24ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
int32 int24lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
int32 int24le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
int32 int24gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
int32 int24ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
int32 int42eq(int32 arg1, int32 arg2) { return(arg1 == arg2); }
int32 int42ne(int32 arg1, int32 arg2) { return(arg1 != arg2); }
int32 int42lt(int32 arg1, int32 arg2) { return(arg1 < arg2); }
int32 int42le(int32 arg1, int32 arg2) { return(arg1 <= arg2); }
int32 int42gt(int32 arg1, int32 arg2) { return(arg1 > arg2); }
int32 int42ge(int32 arg1, int32 arg2) { return(arg1 >= arg2); }
int32 keyfirsteq(int16 *arg1, int16 arg2) { return(*arg1 == arg2); }
/*
* int[24]pl - returns arg1 + arg2
* int[24]mi - returns arg1 - arg2
* int[24]mul - returns arg1 * arg2
* int[24]div - returns arg1 / arg2
*/
int32 int4um(int32 arg) { return(-arg); }
int32 int4pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
int32 int4mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
int32 int4mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
int32 int4div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
int32 int4inc(int32 arg) { return(arg + (int32)1); }
int16 int2um(int16 arg) { return(-arg); }
int16 int2pl(int16 arg1, int16 arg2) { return(arg1 + arg2); }
int16 int2mi(int16 arg1, int16 arg2) { return(arg1 - arg2); }
int16 int2mul(int16 arg1, int16 arg2) { return(arg1 * arg2); }
int16 int2div(int16 arg1, int16 arg2) { return(arg1 / arg2); }
int16 int2inc(int16 arg) { return(arg + (int16)1); }
int32 int24pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
int32 int24mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
int32 int24mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
int32 int24div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
int32 int42pl(int32 arg1, int32 arg2) { return(arg1 + arg2); }
int32 int42mi(int32 arg1, int32 arg2) { return(arg1 - arg2); }
int32 int42mul(int32 arg1, int32 arg2) { return(arg1 * arg2); }
int32 int42div(int32 arg1, int32 arg2) { return(arg1 / arg2); }
/*
* int[24]mod - returns arg1 mod arg2
*/
int32 int4mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
int32 int2mod(int16 arg1, int16 arg2) { return(arg1 % arg2); }
int32 int24mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
int32 int42mod(int32 arg1, int32 arg2) { return(arg1 % arg2); }
/*
* int[24]fac - returns arg1!
*/
int32 int4fac(int32 arg1)
{
int32 result;
if (arg1 < 1)
result = 0;
else
for (result = 1; arg1 > 0; --arg1)
result *= arg1;
return(result);
}
int32 int2fac(int16 arg1)
{
int16 result;
if (arg1 < 1)
result = 0;
else
for (result = 1; arg1 > 0; --arg1)
result *= arg1;
return(result);
}
int16 int2larger(int16 arg1, int16 arg2)
{
return ((arg1 > arg2) ? arg1 : arg2);
}
int16 int2smaller(int16 arg1, int16 arg2)
{
return ((arg1 < arg2) ? arg1 : arg2);
}
int32 int4larger(int32 arg1, int32 arg2)
{
return ((arg1 > arg2) ? arg1 : arg2);
}
int32 int4smaller(int32 arg1, int32 arg2)
{
return ((arg1 < arg2) ? arg1 : arg2);
}

View File

@@ -0,0 +1,225 @@
/*-------------------------------------------------------------------------
*
* like.c--
* like expression handling code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* /usr/local/devel/pglite/cvs/src/backend/utils/adt/like.c,v 1.1 1995/07/30 23:55:36 emkxp01 Exp
*
*
* NOTES
* A big hack of the regexp.c code!! Contributed by
* Keith Parks <emkxp01@mtcc.demon.co.uk> (7/95).
*
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h" /* postgres system include file */
#include "utils/elog.h" /* for logging postgres errors */
#include "utils/palloc.h"
#include "utils/builtins.h" /* where the function declarations go */
int like(char *text, char *p);
/*
* interface routines called by the function manager
*/
/*
fixedlen_like:
a generic fixed length like routine
s - the string to match against (not necessarily null-terminated)
p - the pattern
charlen - the length of the string
*/
static bool
fixedlen_like(char *s, struct varlena* p, int charlen)
{
char *sterm, *pterm;
int result;
if (!s || !p)
return FALSE;
/* be sure sterm is null-terminated */
sterm = (char *) palloc(charlen + 1);
memset(sterm, 0, charlen + 1);
strncpy(sterm, s, charlen);
/* p is a text = varlena, not a string so we have to make
* a string from the vl_data field of the struct. */
/* palloc the length of the text + the null character */
pterm = (char *) palloc(VARSIZE(p) - VARHDRSZ + 1);
memmove(pterm, VARDATA(p), VARSIZE(p) - VARHDRSZ);
*(pterm + VARSIZE(p) - VARHDRSZ) = (char)NULL;
/* do the regexp matching */
result = like(sterm, pterm);
pfree(sterm);
pfree(pterm);
return ((bool) result);
}
bool
char2like(uint16 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_like(s, p, 2));
}
bool
char2nlike(uint16 arg1, struct varlena *p)
{
return (!char2like(arg1, p));
}
bool
char4like(uint32 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_like(s, p, 4));
}
bool
char4nlike(uint32 arg1, struct varlena *p)
{
return (!char4like(arg1, p));
}
bool
char8like(char *s, struct varlena *p)
{
return (fixedlen_like(s, p, 8));
}
bool
char8nlike(char *s, struct varlena *p)
{
return (!char8like(s, p));
}
bool
char16like(char *s, struct varlena *p)
{
return (fixedlen_like(s, p, 16));
}
bool
char16nlike(char *s, struct varlena *p)
{
return (!char16like(s, p));
}
bool
namelike(NameData *n, struct varlena *p)
{
return (fixedlen_like(n->data, p, NAMEDATALEN));
}
bool
namenlike(NameData *s, struct varlena *p)
{
return (!namelike(s, p));
}
bool
textlike(struct varlena *s, struct varlena *p)
{
return (fixedlen_like(VARDATA(s), p, VARSIZE(s) - VARHDRSZ));
}
bool textnlike(struct varlena *s, struct varlena *p)
{
return (!textlike(s, p));
}
/* $Revision: 1.1.1.1 $
** "like.c" A first attempt at a LIKE operator for Postgres95.
**
** Originally written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
** Rich $alz is now <rsalz@bbn.com>.
** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the LABORT code.
**
** This code was shamelessly stolen from the "pql" code by myself and
** slightly modified :)
**
** All references to the word "star" were replaced by "percent"
** All references to the word "wild" were replaced by "like"
**
** All the nice shell RE matching stuff was replaced by just "_" and "%"
**
** As I don't have a copy of the SQL standard handy I wasn't sure whether
** to leave in the '\' escape character handling. (I suspect the standard
** handles "%%" as a single literal percent)
**
** Keith Parks. <keith@mtcc.demon.co.uk>
**
** [SQL92 lets you specify the escape character by saying
** LIKE <pattern> ESCAPE <escape character>. We are a small operation
** so we force you to use '\'. - ay 7/95]
**
*/
#define LIKE_TRUE 1
#define LIKE_FALSE 0
#define LIKE_ABORT -1
/*
** Match text and p, return LIKE_TRUE, LIKE_FALSE, or LIKE_ABORT.
*/
static int
DoMatch(register char *text, register char *p)
{
register int matched;
for ( ; *p; text++, p++) {
if (*text == '\0' && *p != '%')
return LIKE_ABORT;
switch (*p) {
case '\\':
/* Literal match with following character. */
p++;
/* FALLTHROUGH */
default:
if (*text != *p)
return LIKE_FALSE;
continue;
case '_':
/* Match anything. */
continue;
case '%':
while (*++p == '%')
/* Consecutive percents act just like one. */
continue;
if (*p == '\0')
/* Trailing percent matches everything. */
return LIKE_TRUE;
while (*text)
if ((matched = DoMatch(text++, p)) != LIKE_FALSE)
return matched;
return LIKE_ABORT;
}
}
return *text == '\0';
}
/*
** User-level routine. Returns TRUE or FALSE.
*/
int
like(char *text, char *p)
{
if (p[0] == '%' && p[1] == '\0')
return TRUE;
return (DoMatch(text, p) == LIKE_TRUE);
}

View File

@@ -0,0 +1,96 @@
/*-------------------------------------------------------------------------
*
* misc.c--
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/misc.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <sys/file.h>
#include "postgres.h"
#include "utils/datum.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#if !defined(PORTNAME_linux) && !defined(PORTNAME_BSD44_derived) && \
!defined(PORTNAME_irix5) && !defined(PORTNAME_bsdi) && !defined(PORTNAME_aix)
extern int random();
extern int srandom(unsigned);
#endif
/*-------------------------------------------------------------------------
* Check if data is Null
*/
bool
NullValue(Datum value, bool *isNull)
{
if (*isNull) {
*isNull = false;
return(true);
}
return(false);
}
/*----------------------------------------------------------------------*
* check if data is not Null *
*--------------------------------------------------------------------- */
bool
NonNullValue(Datum value, bool *isNull)
{
if (*isNull) {
*isNull = false;
return(false);
}
return(true);
}
/*
* oidrand (oid o, int4 X)-
* takes in an oid and a int4 X, and will return 'true'
* about 1/X of the time.
* Useful for doing random sampling or subsetting.
* if X == 0, this will always return true;
*
* Example use:
* select * from TEMP where oidrand(TEMP.oid, 10)
* will return about 1/10 of the tuples in TEMP
*
*/
bool
oidrand(Oid o, int32 X)
{
bool result;
if (X == 0) return true;
result = (random() % X == 0);
return result;
}
/*
oidsrand(int32 X) -
seeds the random number generator
always return true
*/
bool
oidsrand(int32 X)
{
srand(X);
return true;
}
int32
userfntest(int i)
{
return (i);
}

View File

@@ -0,0 +1,866 @@
/*-------------------------------------------------------------------------
*
* nabstime.c--
* parse almost any absolute date getdate(3) can (& some it can't)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/nabstime.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include "postgres.h"
#include "access/xact.h"
#include "utils/nabstime.h"
#include "utils/palloc.h"
#define MAXDATEFIELDS 25
#define ISSPACE(c) ((c) == ' ' || (c) == '\n' || (c) == '\t')
/* this is fast but dirty. note the return's in the middle. */
#define GOBBLE_NUM(cp, c, x, ip) \
(c) = *(cp)++; \
if ((c) < '0' || (c) > '9') \
return -1; /* missing digit */ \
(x) = (c) - '0'; \
(c) = *(cp)++; \
if ((c) >= '0' && (c) <= '9') { \
(x) = 10*(x) + (c) - '0'; \
(c) = *(cp)++; \
} \
if ((c) != ':' && (c) != '\0' && !ISSPACE(c)) \
return -1; /* missing colon */ \
*(ip) = (x) /* N.B.: no semi-colon here */
#define EPOCH 1970
#define DAYS_PER_400YRS (time_t)146097
#define DAYS_PER_4YRS (time_t)1461
#define SECS_PER_DAY 86400
#define SECS_PER_HOUR 3600
#define DIVBY4(n) ((n) >> 2)
#define YRNUM(c, y) (DIVBY4(DAYS_PER_400YRS*(c)) + DIVBY4(DAYS_PER_4YRS*(y)))
#define DAYNUM(c,y,mon,d) (YRNUM((c), (y)) + mdays[mon] + (d))
#define EPOCH_DAYNUM DAYNUM(19, 69, 10, 1) /* really January 1, 1970 */
#define MIN_DAYNUM -24856 /* December 13, 1901 */
#define MAX_DAYNUM 24854 /* January 18, 2038 */
/* definitions for squeezing values into "value" */
#define ABS_SIGNBIT 0200
#define VALMASK 0177
#define NEG(n) ((n)|ABS_SIGNBIT)
#define SIGNEDCHAR(c) ((c)&ABS_SIGNBIT? -((c)&VALMASK): (c))
#define FROMVAL(tp) (-SIGNEDCHAR((tp)->value) * 10) /* uncompress */
#define TOVAL(tp, v) ((tp)->value = ((v) < 0? NEG((-(v))/10): (v)/10))
#define IsLeapYear(yr) ((yr%4) == 0)
char nmdays[] = {
0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};
/* days since start of year. mdays[0] is March, mdays[11] is February */
static short mdays[] = {
0, 31, 61, 92, 122, 153, 184, 214, 245, 275, 306, 337
};
/* exports */
static int dtok_numparsed;
/*
* to keep this table reasonably small, we divide the lexval for TZ and DTZ
* entries by 10 and truncate the text field at MAXTOKLEN characters.
* the text field is not guaranteed to be NUL-terminated.
*/
static datetkn datetktbl[] = {
/* text token lexval */
{ "acsst", DTZ, 63}, /* Cent. Australia */
{ "acst", TZ, 57}, /* Cent. Australia */
{ "adt", DTZ, NEG(18)}, /* Atlantic Daylight Time */
{ "aesst", DTZ, 66}, /* E. Australia */
{ "aest", TZ, 60}, /* Australia Eastern Std Time */
{ "ahst", TZ, 60}, /* Alaska-Hawaii Std Time */
{ "am", AMPM, AM},
{ "apr", MONTH, 4},
{ "april", MONTH, 4},
{ "ast", TZ, NEG(24)}, /* Atlantic Std Time (Canada) */
{ "at", PG_IGNORE, 0}, /* "at" (throwaway) */
{ "aug", MONTH, 8},
{ "august", MONTH, 8},
{ "awsst", DTZ, 54}, /* W. Australia */
{ "awst", TZ, 48}, /* W. Australia */
{ "bst", TZ, 6}, /* British Summer Time */
{ "bt", TZ, 18}, /* Baghdad Time */
{ "cadt", DTZ, 63}, /* Central Australian DST */
{ "cast", TZ, 57}, /* Central Australian ST */
{ "cat", TZ, NEG(60)}, /* Central Alaska Time */
{ "cct", TZ, 48}, /* China Coast */
{ "cdt", DTZ, NEG(30)}, /* Central Daylight Time */
{ "cet", TZ, 6}, /* Central European Time */
{ "cetdst", DTZ, 12}, /* Central European Dayl.Time */
{ "cst", TZ, NEG(36)}, /* Central Standard Time */
{ "dec", MONTH, 12},
{ "decemb", MONTH, 12},
{ "dnt", TZ, 6}, /* Dansk Normal Tid */
{ "dst", PG_IGNORE, 0},
{ "east", TZ, NEG(60)}, /* East Australian Std Time */
{ "edt", DTZ, NEG(24)}, /* Eastern Daylight Time */
{ "eet", TZ, 12}, /* East. Europe, USSR Zone 1 */
{ "eetdst", DTZ, 18}, /* Eastern Europe */
{ "est", TZ, NEG(30)}, /* Eastern Standard Time */
{ "feb", MONTH, 2},
{ "februa", MONTH, 2},
{ "fri", PG_IGNORE, 5},
{ "friday", PG_IGNORE, 5},
{ "fst", TZ, 6}, /* French Summer Time */
{ "fwt", DTZ, 12}, /* French Winter Time */
{ "gmt", TZ, 0}, /* Greenwish Mean Time */
{ "gst", TZ, 60}, /* Guam Std Time, USSR Zone 9 */
{ "hdt", DTZ, NEG(54)}, /* Hawaii/Alaska */
{ "hmt", DTZ, 18}, /* Hellas ? ? */
{ "hst", TZ, NEG(60)}, /* Hawaii Std Time */
{ "idle", TZ, 72}, /* Intl. Date Line, East */
{ "idlw", TZ, NEG(72)}, /* Intl. Date Line, West */
{ "ist", TZ, 12}, /* Israel */
{ "it", TZ, 22}, /* Iran Time */
{ "jan", MONTH, 1},
{ "januar", MONTH, 1},
{ "jst", TZ, 54}, /* Japan Std Time,USSR Zone 8 */
{ "jt", TZ, 45}, /* Java Time */
{ "jul", MONTH, 7},
{ "july", MONTH, 7},
{ "jun", MONTH, 6},
{ "june", MONTH, 6},
{ "kst", TZ, 54}, /* Korea Standard Time */
{ "ligt", TZ, 60}, /* From Melbourne, Australia */
{ "mar", MONTH, 3},
{ "march", MONTH, 3},
{ "may", MONTH, 5},
{ "mdt", DTZ, NEG(36)}, /* Mountain Daylight Time */
{ "mest", DTZ, 12}, /* Middle Europe Summer Time */
{ "met", TZ, 6}, /* Middle Europe Time */
{ "metdst", DTZ, 12}, /* Middle Europe Daylight Time*/
{ "mewt", TZ, 6}, /* Middle Europe Winter Time */
{ "mez", TZ, 6}, /* Middle Europe Zone */
{ "mon", PG_IGNORE, 1},
{ "monday", PG_IGNORE, 1},
{ "mst", TZ, NEG(42)}, /* Mountain Standard Time */
{ "mt", TZ, 51}, /* Moluccas Time */
{ "ndt", DTZ, NEG(15)}, /* Nfld. Daylight Time */
{ "nft", TZ, NEG(21)}, /* Newfoundland Standard Time */
{ "nor", TZ, 6}, /* Norway Standard Time */
{ "nov", MONTH, 11},
{ "novemb", MONTH, 11},
{ "nst", TZ, NEG(21)}, /* Nfld. Standard Time */
{ "nt", TZ, NEG(66)}, /* Nome Time */
{ "nzdt", DTZ, 78}, /* New Zealand Daylight Time */
{ "nzst", TZ, 72}, /* New Zealand Standard Time */
{ "nzt", TZ, 72}, /* New Zealand Time */
{ "oct", MONTH, 10},
{ "octobe", MONTH, 10},
{ "on", PG_IGNORE, 0}, /* "on" (throwaway) */
{ "pdt", DTZ, NEG(42)}, /* Pacific Daylight Time */
{ "pm", AMPM, PM},
{ "pst", TZ, NEG(48)}, /* Pacific Standard Time */
{ "sadt", DTZ, 63}, /* S. Australian Dayl. Time */
{ "sast", TZ, 57}, /* South Australian Std Time */
{ "sat", PG_IGNORE, 6},
{ "saturd", PG_IGNORE, 6},
{ "sep", MONTH, 9},
{ "sept", MONTH, 9},
{ "septem", MONTH, 9},
{ "set", TZ, NEG(6)}, /* Seychelles Time ?? */
{ "sst", DTZ, 12}, /* Swedish Summer Time */
{ "sun", PG_IGNORE, 0},
{ "sunday", PG_IGNORE, 0},
{ "swt", TZ, 6}, /* Swedish Winter Time */
{ "thu", PG_IGNORE, 4},
{ "thur", PG_IGNORE, 4},
{ "thurs", PG_IGNORE, 4},
{ "thursd", PG_IGNORE, 4},
{ "tue", PG_IGNORE, 2},
{ "tues", PG_IGNORE, 2},
{ "tuesda", PG_IGNORE, 2},
{ "ut", TZ, 0},
{ "utc", TZ, 0},
{ "wadt", DTZ, 48}, /* West Australian DST */
{ "wast", TZ, 42}, /* West Australian Std Time */
{ "wat", TZ, NEG(6)}, /* West Africa Time */
{ "wdt", DTZ, 54}, /* West Australian DST */
{ "wed", PG_IGNORE, 3},
{ "wednes", PG_IGNORE, 3},
{ "weds", PG_IGNORE, 3},
{ "wet", TZ, 0}, /* Western Europe */
{ "wetdst", DTZ, 6}, /* Western Europe */
{ "wst", TZ, 48}, /* West Australian Std Time */
{ "ydt", DTZ, NEG(48)}, /* Yukon Daylight Time */
{ "yst", TZ, NEG(54)}, /* Yukon Standard Time */
{ "zp4", TZ, NEG(24)}, /* GMT +4 hours. */
{ "zp5", TZ, NEG(30)}, /* GMT +5 hours. */
{ "zp6", TZ, NEG(36)}, /* GMT +6 hours. */
};
static unsigned int szdatetktbl = sizeof datetktbl / sizeof datetktbl[0];
/*
* parse and convert absolute date in timestr (the normal interface)
*
* Returns the number of seconds since epoch (January 1 1970 GMT)
*/
AbsoluteTime
nabstimein(char* timestr)
{
int tz = 0;
struct tm date;
if (!timestr)
return INVALID_ABSTIME;
while (ISSPACE(*timestr))
++timestr;
if (!strcasecmp(timestr, "epoch"))
return EPOCH_ABSTIME;
if (!strcasecmp(timestr, "now"))
return GetCurrentTransactionStartTime();
if (!strcasecmp(timestr, "current"))
return CURRENT_ABSTIME;
if (!strcasecmp(timestr, "infinity"))
return NOEND_ABSTIME;
if (!strcasecmp(timestr, "-infinity"))
return NOSTART_ABSTIME;
if (prsabsdate(timestr, &date, &tz) < 0)
return INVALID_ABSTIME;
return dateconv(&date, tz);
}
/*
* just parse the absolute date in timestr and get back a broken-out date.
*/
int
prsabsdate(char *timestr,
struct tm *tm,
int *tzp) /* - minutes west */
{
register int nf;
char *fields[MAXDATEFIELDS];
static char delims[] = "- \t\n/,";
nf = split(timestr, fields, MAXDATEFIELDS, delims+1);
if (nf > MAXDATEFIELDS)
return -1;
if (tryabsdate(fields, nf, tm, tzp) < 0) {
register char *p = timestr;
/*
* could be a DEC-date; glue it all back together, split it
* with dash as a delimiter and try again. Yes, this is a
* hack, but so are DEC-dates.
*/
while (--nf > 0) {
while (*p++ != '\0')
;
p[-1] = ' ';
}
nf = split(timestr, fields, MAXDATEFIELDS, delims);
if (nf > MAXDATEFIELDS)
return -1;
if (tryabsdate(fields, nf, tm, tzp) < 0)
return -1;
}
return 0;
}
/*
* try to parse pre-split timestr as an absolute date
*/
int
tryabsdate(char *fields[], int nf, struct tm *tm, int *tzp)
{
register int i;
register datetkn *tp;
register long flg = 0, ty;
int mer = HR24, bigval = -1;
#ifndef USE_POSIX_TIME
struct timeb now; /* the old V7-ism */
(void) ftime(&now);
*tzp = now.timezone;
#else /* USE_POSIX_TIME */
#if defined(PORTNAME_hpux) || \
defined(PORTNAME_aix) || \
defined(PORTNAME_irix5) || \
defined(WIN32) || \
defined(PORTNAME_sparc_solaris)
tzset();
#ifndef WIN32
*tzp = timezone / 60; /* this is an X/Open-ism */
#else
*tzp = _timezone / 60; /* this is an X/Open-ism */
#endif /* WIN32 */
#else /* PORTNAME_hpux || PORTNAME_aix || PORTNAME_sparc_solaris || PORTNAME_irix5 */
time_t now = time((time_t *) NULL);
struct tm *tmnow = localtime(&now);
*tzp = - tmnow->tm_gmtoff / 60; /* tm_gmtoff is Sun/DEC-ism */
#endif /* PORTNAME_hpux || PORTNAME_aix */
#endif /* USE_POSIX_TIME */
tm->tm_mday = tm->tm_mon = tm->tm_year = -1; /* mandatory */
tm->tm_hour = tm->tm_min = tm->tm_sec = 0;
tm->tm_isdst = -1; /* assume we don't know. */
dtok_numparsed = 0;
for (i = 0; i < nf; i++) {
if (fields[i][0] == '\0')
continue;
tp = datetoktype(fields[i], &bigval);
ty = (1L << tp->type) & ~(1L << PG_IGNORE);
if (flg&ty)
return -1; /* repeated type */
flg |= ty;
switch (tp->type) {
case YEAR:
tm->tm_year = bigval;
break;
case DAY:
tm->tm_mday = bigval;
break;
case MONTH:
tm->tm_mon = tp->value;
break;
case TIME:
if (parsetime(fields[i], tm) < 0)
return -1;
break;
case DTZ:
tm->tm_isdst++;
/* FALLTHROUGH */
case TZ:
*tzp = FROMVAL(tp);
break;
case PG_IGNORE:
break;
case AMPM:
mer = tp->value;
break;
default:
return -1; /* bad token type: CANTHAPPEN */
}
}
if (tm->tm_year == -1 || tm->tm_mon == -1 || tm->tm_mday == -1)
return -1; /* missing component */
if (mer == PM)
tm->tm_hour += 12;
return 0;
}
/* return -1 on failure */
int
parsetime(char *time, struct tm *tm)
{
register char c;
register int x;
tm->tm_sec = 0;
GOBBLE_NUM(time, c, x, &tm->tm_hour);
if (c != ':')
return -1; /* only hour; too short */
GOBBLE_NUM(time, c, x, &tm->tm_min);
if (c != ':')
return 0; /* no seconds; okay */
GOBBLE_NUM(time, c, x, &tm->tm_sec);
/* this may be considered too strict. garbage at end of time? */
return (c == '\0' || ISSPACE(c)? 0: -1);
}
/*
* split - divide a string into fields, like awk split()
*/
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;
sep = " \t"; /* 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 */
}
/*
* Given an AbsoluteTime return the English text version of the date
*/
char *
nabstimeout(AbsoluteTime time)
{
/*
* Fri Jan 28 23:05:29 1994 PST
* 0 1 2
* 12345678901234567890123456789
*
* we allocate some extra -- timezones are usually 3 characters but
* this is not in the POSIX standard...
*/
char buf[40];
char* result;
switch (time) {
case EPOCH_ABSTIME: (void) strcpy(buf, "epoch"); break;
case INVALID_ABSTIME: (void) strcpy(buf, "Invalid Abstime"); break;
case CURRENT_ABSTIME: (void) strcpy(buf, "current"); break;
case NOEND_ABSTIME: (void) strcpy(buf, "infinity"); break;
case NOSTART_ABSTIME: (void) strcpy(buf, "-infinity"); break;
default:
/* hack -- localtime happens to work for negative times */
(void) strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y %Z",
localtime((time_t *) &time));
break;
}
result = (char*)palloc(strlen(buf) + 1);
strcpy(result, buf);
return result;
}
/* turn a (struct tm) and a few variables into a time_t, with range checking */
AbsoluteTime
dateconv(register struct tm *tm, int zone)
{
tm->tm_wday = tm->tm_yday = 0;
/* validate, before going out of range on some members */
if (tm->tm_year < 0 || tm->tm_mon < 1 || tm->tm_mon > 12 ||
tm->tm_mday < 1 || tm->tm_hour < 0 || tm->tm_hour >= 24 ||
tm->tm_min < 0 || tm->tm_min > 59 ||
tm->tm_sec < 0 || tm->tm_sec > 59)
return -1;
/*
* zone should really be -zone, and tz should be set to tp->value, not
* -tp->value. Or the table could be fixed.
*/
tm->tm_min += zone; /* mktime lets it be out of range */
/* convert to seconds */
return qmktime(tm);
}
/*
* near-ANSI qmktime suitable for use by dateconv; not necessarily as paranoid
* as ANSI requires, and it may not canonicalise the struct tm. Ignores tm_wday
* and tm_yday.
*/
time_t
qmktime(struct tm *tp)
{
register int mon = tp->tm_mon;
register int day = tp->tm_mday, year = tp->tm_year;
register time_t daynum;
time_t secondnum;
register int century;
/* If it was a 2 digit year */
if (year < 100)
year += 1900;
/*
* validate day against days-per-month table, with leap-year
* correction
*/
if (day > nmdays[mon])
if (mon != 2 || year % 4 == 0 &&
(year % 100 != 0 || year % 400 == 0) && day > 29)
return -1; /* day too large for month */
/* split year into century and year-of-century */
century = year / 100;
year %= 100;
/*
* We calculate the day number exactly, assuming the calendar has
* always had the current leap year rules. (The leap year rules are
* to compensate for the fact that the Earth's revolution around the
* Sun takes 365.2425 days). We first need to rotate months so March
* is 0, since we want the last month to have the reduced number of
* days.
*/
if (mon > 2)
mon -= 3;
else {
mon += 9;
if (year == 0) {
century--;
year = 99;
} else
--year;
}
daynum = -EPOCH_DAYNUM + DAYNUM(century, year, mon, day);
/* check for time out of range */
if (daynum < MIN_DAYNUM || daynum > MAX_DAYNUM)
return INVALID_ABSTIME;
/* convert to seconds */
secondnum =
tp->tm_sec + (tp->tm_min +(daynum*24 + tp->tm_hour)*60)*60;
/* check for overflow */
if ((daynum == MAX_DAYNUM && secondnum < 0) ||
(daynum == MIN_DAYNUM && secondnum > 0))
return INVALID_ABSTIME;
/* check for "current", "infinity", "-infinity" */
if (!AbsoluteTimeIsReal(secondnum))
return INVALID_ABSTIME;
/* daylight correction */
if (tp->tm_isdst < 0) /* unknown; find out */
{
struct tm *result;
/* NT returns NULL for any time before 1/1/70 */
result = localtime(&secondnum);
if (result == NULL)
return INVALID_ABSTIME;
else
tp->tm_isdst = result->tm_isdst;
}
if (tp->tm_isdst > 0)
secondnum -= 60*60;
return secondnum;
}
datetkn *
datetoktype(char *s, int *bigvalp)
{
register char *cp = s;
register char c = *cp;
static datetkn t;
register datetkn *tp = &t;
if (isascii(c) && isdigit(c)) {
register int len = strlen(cp);
if (len > 3 && (cp[1] == ':' || cp[2] == ':'))
tp->type = TIME;
else {
if (bigvalp != NULL)
/* won't fit in tp->value */
*bigvalp = atoi(cp);
if (len == 4)
tp->type = YEAR;
else if (++dtok_numparsed == 1)
tp->type = DAY;
else
tp->type = YEAR;
}
} else if (c == '-' || c == '+') {
register int val = atoi(cp + 1);
register int hr = val / 100;
register int min = val % 100;
val = hr*60 + min;
if (c == '-')
val = -val;
tp->type = TZ;
TOVAL(tp, val);
} else {
char lowtoken[TOKMAXLEN+1];
register char *ltp = lowtoken, *endltp = lowtoken+TOKMAXLEN;
/* copy to lowtoken to avoid modifying s */
while ((c = *cp++) != '\0' && ltp < endltp)
*ltp++ = (isascii(c) && isupper(c)? tolower(c): c);
*ltp = '\0';
tp = datebsearch(lowtoken, datetktbl, szdatetktbl);
if (tp == NULL) {
tp = &t;
tp->type = PG_IGNORE;
}
}
return tp;
}
/*
* Binary search -- from Knuth (6.2.1) Algorithm B. Special case like this
* is WAY faster than the generic bsearch().
*/
datetkn *
datebsearch(char *key, datetkn *base, unsigned int nel)
{
register datetkn *last = base + nel - 1, *position;
register int result;
while (last >= base) {
position = base + ((last - base) >> 1);
result = key[0] - position->token[0];
if (result == 0) {
result = strncmp(key, position->token, TOKMAXLEN);
if (result == 0)
return position;
}
if (result < 0)
last = position - 1;
else
base = position + 1;
}
return 0;
}
/*
* AbsoluteTimeIsBefore -- true iff time1 is before time2.
*/
bool
AbsoluteTimeIsBefore(AbsoluteTime time1, AbsoluteTime time2)
{
AbsoluteTime tm = GetCurrentTransactionStartTime();
Assert(AbsoluteTimeIsValid(time1));
Assert(AbsoluteTimeIsValid(time2));
if ((time1 == CURRENT_ABSTIME) || (time2 == CURRENT_ABSTIME))
return false;
if (time1 == CURRENT_ABSTIME)
return (tm < time2);
if (time2 == CURRENT_ABSTIME)
return (time1 < tm);
return (time1 < time2);
}
bool
AbsoluteTimeIsAfter(AbsoluteTime time1, AbsoluteTime time2)
{
AbsoluteTime tm = GetCurrentTransactionStartTime();
Assert(AbsoluteTimeIsValid(time1));
Assert(AbsoluteTimeIsValid(time2));
if ((time1 == CURRENT_ABSTIME) || (time2 == CURRENT_ABSTIME))
return false;
if (time1 == CURRENT_ABSTIME)
return (tm > time2);
if (time2 == CURRENT_ABSTIME)
return (time1 > tm);
return (time1 > time2);
}
/*
* abstimeeq - returns 1, iff arguments are equal
* abstimene - returns 1, iff arguments are not equal
* abstimelt - returns 1, iff t1 less than t2
* abstimegt - returns 1, iff t1 greater than t2
* abstimele - returns 1, iff t1 less than or equal to t2
* abstimege - returns 1, iff t1 greater than or equal to t2
*
*/
int32
abstimeeq(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 == t2);
}
int32
abstimene(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 != t2);
}
int32
abstimelt(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 < t2);
}
int32
abstimegt(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 > t2);
}
int32
abstimele(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 <= t2);
}
int32
abstimege(AbsoluteTime t1, AbsoluteTime t2)
{
if (t1 == INVALID_ABSTIME || t2 == INVALID_ABSTIME)
return 0;
if (t1 == CURRENT_ABSTIME)
t1 = GetCurrentTransactionStartTime();
if (t2 == CURRENT_ABSTIME)
t2 = GetCurrentTransactionStartTime();
return(t1 >= t2);
}

View File

@@ -0,0 +1,198 @@
/*-------------------------------------------------------------------------
*
* name.c--
* Functions for the built-in type "name".
* name replaces char16 and is carefully implemented so that it
* is a string of length NAMEDATALEN. DO NOT use hard-coded constants anywhere
* always use NAMEDATALEN as the symbolic constant! - jolly 8/21/95
*
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/name.c,v 1.1.1.1 1996/07/09 06:22:04 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "utils/builtins.h" /* where the declarations go */
#include "utils/palloc.h" /* where the declarations go */
/*****************************************************************************
* USER I/O ROUTINES (none) *
*****************************************************************************/
/*
* namein - converts "..." to internal representation
*
* Note:
* Currently if strlen(s) < NAMEDATALEN, the extra chars are nulls
*/
NameData *namein(char *s)
{
NameData *result;
if (s == NULL)
return(NULL);
result = (NameData*) palloc(NAMEDATALEN);
/* always keep it null-padded */
memset(result->data, 0, NAMEDATALEN);
(void) strncpy(result->data, s, NAMEDATALEN-1);
return(result);
}
/*
* nameout - converts internal reprsentation to "..."
*/
char *nameout(NameData *s)
{
if (s == NULL)
return "-";
else
return pstrdup(s->data);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
/*
* nameeq - returns 1 iff arguments are equal
* namene - returns 1 iff arguments are not equal
*
* BUGS:
* Assumes that "xy\0\0a" should be equal to "xy\0b".
* If not, can do the comparison backwards for efficiency.
*
* namelt - returns 1 iff a < b
* namele - returns 1 iff a <= b
* namegt - returns 1 iff a < b
* namege - returns 1 iff a <= b
*
*/
int32 nameeq(NameData *arg1, NameData *arg2)
{
if (!arg1 || !arg2)
return 0;
else
return (strncmp(arg1->data, arg2->data, NAMEDATALEN) == 0);
}
int32 namene(NameData *arg1, NameData *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return(strncmp(arg1->data, arg2->data, NAMEDATALEN) != 0);
}
int32 namelt(NameData *arg1, NameData *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1->data, arg2->data, NAMEDATALEN) < 0));
}
int32 namele(NameData *arg1, NameData *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1->data, arg2->data, NAMEDATALEN) <= 0));
}
int32 namegt(NameData *arg1, NameData *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1->data, arg2->data, NAMEDATALEN) > 0));
}
int32 namege(NameData *arg1, NameData *arg2)
{
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
return((int32) (strncmp(arg1->data, arg2->data, NAMEDATALEN) >= 0));
}
/* (see char.c for comparison/operation routines) */
int namecpy(Name n1, Name n2)
{
if (!n1 || !n2)
return(-1);
(void) strncpy(n1->data, n2->data, NAMEDATALEN);
return(0);
}
int namecat(Name n1, Name n2)
{
return(namestrcat(n1, n2->data)); /* n2 can't be any longer than n1 */
}
int namecmp(Name n1, Name n2)
{
return(strncmp(n1->data, n2->data, NAMEDATALEN));
}
int
namestrcpy(Name name, char *str)
{
if (!name || !str)
return(-1);
memset(name->data, 0, sizeof(NameData));
(void) strncpy(name->data, str, NAMEDATALEN);
return(0);
}
int namestrcat(Name name, char *str)
{
int i;
char *p, *q;
if (!name || !str)
return(-1);
for (i = 0, p = name->data; i < NAMEDATALEN && *p; ++i, ++p)
;
for (q = str; i < NAMEDATALEN; ++i, ++p, ++q) {
*p = *q;
if (!*q)
break;
}
return(0);
}
int
namestrcmp(Name name, char *str)
{
if (!name && !str)
return(0);
if (!name)
return(-1); /* NULL < anything */
if (!str)
return(1); /* NULL < anything */
return(strncmp(name->data, str, NAMEDATALEN));
}
/*****************************************************************************
* PRIVATE ROUTINES *
*****************************************************************************/
uint32
NameComputeLength(Name name)
{
char *charP;
int length;
for (length = 0, charP = name->data;
length < NAMEDATALEN && *charP != '\0';
length++, charP++) {
;
}
return (uint32)length;
}

View File

@@ -0,0 +1,124 @@
/*-------------------------------------------------------------------------
*
* not_in.c--
* Executes the "not_in" operator for any data type
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
/*
*
* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
* X HACK WARNING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! X
* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
*
* This code is the OLD not-in code that is HACKED
* into place until operators that can have arguments as
* columns are ******REALLY****** implemented!!!!!!!!!!!
*
*/
#include <stdio.h>
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/htup.h"
#include "access/relscan.h"
#include "utils/rel.h"
#include "utils/elog.h"
#include "utils/builtins.h" /* where function decls go */
/* ----------------------------------------------------------------
*
* ----------------------------------------------------------------
*/
bool
int4notin(int16 not_in_arg, char *relation_and_attr)
{
Relation relation_to_scan;
int left_side_argument, integer_value;
HeapTuple current_tuple;
HeapScanDesc scan_descriptor;
bool dummy, retval;
int attrid;
char *relation, *attribute;
char my_copy[32];
Datum value;
NameData relNameData;
ScanKeyData skeyData;
strcpy(my_copy, relation_and_attr);
relation = (char *) strtok(my_copy, ".");
attribute = (char *) strtok(NULL, ".");
/* fetch tuple OID */
left_side_argument = not_in_arg;
/* Open the relation and get a relation descriptor */
namestrcpy(&relNameData,relation);
relation_to_scan = heap_openr(relNameData.data);
attrid = my_varattno(relation_to_scan, attribute);
/* the last argument should be a ScanKey, not an integer! - jolly*/
/* it looks like the arguments are out of order, too */
/* but skeyData is never initialized! does this work?? - ay 2/95 */
scan_descriptor = heap_beginscan(relation_to_scan, false, NULL, 0,
&skeyData);
retval = true;
/* do a scan of the relation, and do the check */
for (current_tuple = heap_getnext(scan_descriptor, 0, NULL);
current_tuple != NULL && retval;
current_tuple = heap_getnext(scan_descriptor, 0, NULL))
{
value = PointerGetDatum(heap_getattr(current_tuple,
InvalidBuffer,
(AttrNumber) attrid,
RelationGetTupleDescriptor(relation_to_scan),
&dummy));
integer_value = DatumGetInt16(value);
if (left_side_argument == integer_value)
{
retval = false;
}
}
/* close the relation */
heap_close(relation_to_scan);
return(retval);
}
bool oidnotin(Oid the_oid, char *compare)
{
if (the_oid == InvalidOid)
return false;
return(int4notin(the_oid, compare));
}
/*
* XXX
* If varattno (in parser/catalog_utils.h) ever is added to
* cinterface.a, this routine should go away
*/
int my_varattno(Relation rd, char *a)
{
int i;
for (i = 0; i < rd->rd_rel->relnatts; i++) {
if (!namestrcmp(&rd->rd_att->attrs[i]->attname, a)) {
return(i+1);
}
}
return(-1);
}

View File

@@ -0,0 +1,401 @@
/*-------------------------------------------------------------------------
*
* numutils.c--
* utility functions for I/O of built-in numeric types.
*
* integer: itoa, ltoa
* floating point: ftoa, atof1
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/numutils.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <errno.h>
#include <math.h>
#include "postgres.h"
#include "utils/builtins.h" /* where the declarations go */
#include "utils/elog.h"
int32
pg_atoi(char *s, int size, int c)
{
long l;
char *badp = (char *) NULL;
Assert(s);
errno = 0;
l = strtol(s, &badp, 10);
if (errno) /* strtol must set ERANGE */
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
if (badp && *badp && (*badp != c))
elog(WARN, "pg_atoi: error in \"%s\": can\'t parse \"%s\"", s, badp);
switch (size) {
case sizeof(int32):
#ifdef HAS_LONG_LONG
/* won't get ERANGE on these with 64-bit longs... */
if (l < -0x80000000L) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
if (l > 0x7fffffffL) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
#endif /* HAS_LONG_LONG */
break;
case sizeof(int16):
if (l < -0x8000) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
if (l > 0x7fff) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
break;
case sizeof(int8):
if (l < -0x80) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
if (l > 0x7f) {
errno = ERANGE;
elog(WARN, "pg_atoi: error reading \"%s\": %m", s);
}
break;
default:
elog(WARN, "pg_atoi: invalid result size: %d", size);
}
return((int32) l);
}
/*
* itoa - converts a short int to its string represention
*
* Note:
* previously based on ~ingres/source/gutil/atoi.c
* now uses vendor's sprintf conversion
*/
void
itoa(int i, char *a)
{
sprintf(a, "%hd", (short)i);
}
/*
* ltoa - converts a long int to its string represention
*
* Note:
* previously based on ~ingres/source/gutil/atoi.c
* now uses vendor's sprintf conversion
*/
void
ltoa(int32 l, char *a)
{
sprintf(a, "%d", l);
}
/*
** ftoa - FLOATING POINT TO ASCII CONVERSION
**
** CODE derived from ingres, ~ingres/source/gutil/ftoa.c
**
** 'Value' is converted to an ascii character string and stored
** into 'ascii'. Ascii should have room for at least 'width' + 1
** characters. 'Width' is the width of the output field (max).
** 'Prec' is the number of characters to put after the decimal
** point. The format of the output string is controlled by
** 'format'.
**
** 'Format' can be:
** e or E: "E" format output
** f or F: "F" format output
** g or G: "F" format output if it will fit, otherwise
** use "E" format.
** n or N: same as G, but decimal points will not always
** be aligned.
**
** If 'format' is upper case, the "E" comes out in upper case;
** otherwise it comes out in lower case.
**
** When the field width is not big enough, it fills the field with
** stars ("*****") and returns zero. Normal return is the width
** of the output field (sometimes shorter than 'width').
*/
int
ftoa(double value, char *ascii, int width, int prec1, char format)
{
#if defined(PORTNAME_BSD44_derived) || defined(PORTNAME_bsdi)
char out[256];
char fmt[256];
int ret;
(void) sprintf(fmt, "%%%d.%d%c", width, prec1, format);
(void) sprintf(out, fmt, value);
if ((ret = strlen(out)) > width) {
memset(ascii, '*', width - 2);
ascii[width] = 0;
return(0);
}
(void) strcpy(ascii, out);
return(ret);
#else
auto int expon;
auto int sign;
register int avail;
register char *a;
register char *p;
char mode;
int lowercase;
int prec;
/* extern char *ecvt(), *fcvt();*/
prec = prec1;
mode = format;
lowercase = 'a' - 'A';
if (mode >= 'a')
mode -= 'a' - 'A';
else
lowercase = 0;
if (mode != 'E') {
/* try 'F' style output */
p = fcvt(value, prec, &expon, &sign);
avail = width;
a = ascii;
/* output sign */
if (sign) {
avail--;
*a++ = '-';
}
/* output '0' before the decimal point */
if (expon <= 0) {
*a++ = '0';
avail--;
}
/* compute space length left after dec pt and fraction */
avail -= prec + 1;
if (mode == 'G')
avail -= 4;
if (avail >= expon) {
/* it fits. output */
while (expon > 0) {
/* output left of dp */
expon--;
if (*p) {
*a++ = *p++;
} else
*a++ = '0';
}
/* output fraction (right of dec pt) */
avail = expon;
goto frac_out;
}
/* won't fit; let's hope for G format */
}
if (mode != 'F') {
/* try to do E style output */
p = ecvt(value, prec + 1, &expon, &sign);
avail = width - 5;
a = ascii;
/* output the sign */
if (sign) {
*a++ = '-';
avail--;
}
}
/* check for field too small */
if (mode == 'F' || avail < prec) {
/* sorry joker, you lose */
a = ascii;
for (avail = width; avail > 0; avail--)
*a++ = '*';
*a = 0;
return (0);
}
/* it fits; output the number */
mode = 'E';
/* output the LHS single digit */
*a++ = *p++;
expon--;
/* output the rhs */
avail = 1;
frac_out:
*a++ = '.';
while (prec > 0) {
prec--;
if (avail < 0) {
avail++;
*a++ = '0';
} else {
if (*p)
*a++ = *p++;
else
*a++ = '0';
}
}
/* output the exponent */
if (mode == 'E') {
*a++ = 'E' + lowercase;
if (expon < 0) {
*a++ = '-';
expon = -expon;
} else
*a++ = '+';
*a++ = (expon / 10) % 10 + '0';
*a++ = expon % 10 + '0';
}
/* output spaces on the end in G format */
if (mode == 'G') {
*a++ = ' ';
*a++ = ' ';
*a++ = ' ';
*a++ = ' ';
}
/* finally, we can return */
*a = 0;
avail = a - ascii;
return (avail);
#endif /* !PORTNAME_BSD44_derived */
}
/*
** atof1 - ASCII TO FLOATING CONVERSION
**
** CODE derived from ~ingres/source/gutil/atof.c
**
** Converts the string 'str' to floating point and stores the
** result into the cell pointed to by 'val'.
**
** The syntax which it accepts is pretty much what you would
** expect. Basically, it is:
** {<sp>} [+|-] {<sp>} {<digit>} [.{digit}] {<sp>} [<exp>]
** where <exp> is "e" or "E" followed by an integer, <sp> is a
** space character, <digit> is zero through nine, [] is zero or
** one, and {} is zero or more.
**
** Parameters:
** str -- string to convert.
** val -- pointer to place to put the result (which
** must be type double).
**
** Returns:
** zero -- ok.
** -1 -- syntax error.
** +1 -- overflow (not implemented).
**
** Side Effects:
** clobbers *val.
*/
int
atof1(char *str, double *val)
{
register char *p;
double v;
double fact;
int minus;
register char c;
int expon;
register int gotmant;
v = 0.0;
p = str;
minus = 0;
/* skip leading blanks */
while ((c = *p) != '\0') {
if (c != ' ')
break;
p++;
}
/* handle possible sign */
switch (c) {
case '-':
minus++;
case '+':
p++;
}
/* skip blanks after sign */
while ((c = *p) != '\0') {
if (c != ' ')
break;
p++;
}
/* start collecting the number to the decimal point */
gotmant = 0;
for (;;) {
c = *p;
if (c < '0' || c > '9')
break;
v = v * 10.0 + (c - '0');
gotmant++;
p++;
}
/* check for fractional part */
if (c == '.') {
fact = 1.0;
for (;;) {
c = *++p;
if (c < '0' || c > '9')
break;
fact *= 0.1;
v += (c - '0') * fact;
gotmant++;
}
}
/* skip blanks before possible exponent */
while ((c = *p) != '\0') {
if (c != ' ')
break;
p++;
}
/* test for exponent */
if (c == 'e' || c == 'E') {
p++;
expon = pg_atoi(p, sizeof(expon), '\0');
if (!gotmant)
v = 1.0;
fact = expon;
v *= pow(10.0, fact);
} else {
/* if no exponent, then nothing */
if (c != 0)
return (-1);
}
/* store the result and exit */
if (minus)
v = -v;
*val = v;
return (0);
}

127
src/backend/utils/adt/oid.c Normal file
View File

@@ -0,0 +1,127 @@
/*-------------------------------------------------------------------------
*
* oid.c--
* Functions for the built-in type Oid.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/oid.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where function declarations go */
#include "utils/elog.h"
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* oid8in - converts "num num ..." to internal form
*
* Note:
* Fills any nonexistent digits with NULL oids.
*/
Oid *oid8in(char *oidString)
{
register Oid (*result)[];
int nums;
if (oidString == NULL)
return(NULL);
result = (Oid (*)[]) palloc(sizeof(Oid [8]));
if ((nums = sscanf(oidString, "%d%d%d%d%d%d%d%d",
*result,
*result + 1,
*result + 2,
*result + 3,
*result + 4,
*result + 5,
*result + 6,
*result + 7)) != 8) {
do
(*result)[nums++] = 0;
while (nums < 8);
}
return((Oid *) result);
}
/*
* oid8out - converts internal form to "num num ..."
*/
char *oid8out(Oid (*oidArray)[])
{
register int num;
register Oid *sp;
register char *rp;
char *result;
if (oidArray == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
return(result);
}
/* assumes sign, 10 digits, ' ' */
rp = result = (char *) palloc(8 * 12);
sp = *oidArray;
for (num = 8; num != 0; num--) {
ltoa(*sp++, rp);
while (*++rp != '\0')
;
*rp++ = ' ';
}
*--rp = '\0';
return(result);
}
Oid oidin(char *s)
{
extern int32 int4in();
return(int4in(s));
}
char *oidout(Oid o)
{
extern char *int4out();
return(int4out(o));
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
int32 oideq(Oid arg1, Oid arg2)
{
return(arg1 == arg2);
}
int32 oidne(Oid arg1, Oid arg2)
{
return(arg1 != arg2);
}
int32 oid8eq(Oid arg1[], Oid arg2[])
{
return (int32)(memcmp(arg1, arg2, 8 * sizeof(Oid)) == 0);
}
bool oideqint4(Oid arg1, int32 arg2)
{
/* oid is unsigned, but int4 is signed */
return (arg2 >= 0 && arg1 == arg2);
}
bool int4eqoid(int32 arg1, Oid arg2)
{
/* oid is unsigned, but int4 is signed */
return (arg1 >= 0 && arg1 == arg2);
}

View File

@@ -0,0 +1,120 @@
/*-------------------------------------------------------------------------
*
* oidint2.c--
* Functions for the built-in type "oidint2".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint2.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* for pg_atoi() */
#include "utils/oidcompos.h" /* where function declarations go */
OidInt2
oidint2in(char *o)
{
OidInt2 oi;
char *p;
oi = (OidInt2) palloc(sizeof(OidInt2Data));
for (p = o; *p != '\0' && *p != '/'; p++)
continue;
oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
if (*p == '\0') {
oi->oi_int2 = 0;
} else {
oi->oi_int2 = (int16) pg_atoi(++p, sizeof(int2), '\0');
}
return (oi);
}
char *
oidint2out(OidInt2 o)
{
char *r;
/*
* -2147483647/-32767
* 0 1
* 1234567890123456789
*/
r = (char *) palloc(19);
sprintf(r, "%d/%d", o->oi_oid, o->oi_int2);
return (r);
}
bool
oidint2lt(OidInt2 o1, OidInt2 o2)
{
return
((bool) (o1->oi_oid < o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int2 < o2->oi_int2)));
}
bool
oidint2le(OidInt2 o1, OidInt2 o2)
{
return ((bool) (o1->oi_oid < o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int2 <= o2->oi_int2)));
}
bool
oidint2eq(OidInt2 o1, OidInt2 o2)
{
return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int2 == o2->oi_int2));
}
bool
oidint2ge(OidInt2 o1, OidInt2 o2)
{
return ((bool) (o1->oi_oid > o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int2 >= o2->oi_int2)));
}
bool
oidint2gt(OidInt2 o1, OidInt2 o2)
{
return ((bool) (o1->oi_oid > o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int2 > o2->oi_int2)));
}
bool
oidint2ne(OidInt2 o1, OidInt2 o2)
{
return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int2 != o2->oi_int2));
}
int
oidint2cmp(OidInt2 o1, OidInt2 o2)
{
if (oidint2lt(o1, o2))
return (-1);
else if (oidint2eq(o1, o2))
return (0);
else
return (1);
}
OidInt2
mkoidint2(Oid v_oid, uint16 v_int2)
{
OidInt2 o;
o = (OidInt2) palloc(sizeof(OidInt2Data));
o->oi_oid = v_oid;
o->oi_int2 = v_int2;
return (o);
}

View File

@@ -0,0 +1,111 @@
/*-------------------------------------------------------------------------
*
* oidint4.c--
* Functions for the built-in type "oidint4".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidint4.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/builtins.h"
#include "utils/oidcompos.h" /* where function declarations go */
OidInt4 oidint4in(char *o)
{
OidInt4 oi;
char *p;
oi = (OidInt4) palloc(sizeof(OidInt4Data));
for (p = o; *p != '\0' && *p != '/'; p++)
continue;
oi->oi_oid = (Oid) pg_atoi(o, sizeof(Oid), '/');
if (*p == '\0') {
oi->oi_int4 = 0;
} else {
oi->oi_int4 = pg_atoi(++p, sizeof(int4), '\0');
}
return (oi);
}
char *oidint4out(OidInt4 o)
{
char *r;
/*
* -2147483647/-2147483647
* 0 1 2
* 123456789012345678901234
*/
r = (char *) palloc(24);
sprintf(r, "%d/%d", o->oi_oid, o->oi_int4);
return (r);
}
bool oidint4lt(OidInt4 o1, OidInt4 o2)
{
return
((bool) (o1->oi_oid < o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int4 < o2->oi_int4)));
}
bool oidint4le(OidInt4 o1, OidInt4 o2)
{
return ((bool) (o1->oi_oid < o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int4 <= o2->oi_int4)));
}
bool oidint4eq(OidInt4 o1, OidInt4 o2)
{
return ((bool) (o1->oi_oid == o2->oi_oid && o1->oi_int4 == o2->oi_int4));
}
bool oidint4ge(OidInt4 o1, OidInt4 o2)
{
return ((bool) (o1->oi_oid > o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int4 >= o2->oi_int4)));
}
bool oidint4gt(OidInt4 o1, OidInt4 o2)
{
return ((bool) (o1->oi_oid > o2->oi_oid ||
(o1->oi_oid == o2->oi_oid && o1->oi_int4 > o2->oi_int4)));
}
bool oidint4ne(OidInt4 o1, OidInt4 o2)
{
return ((bool) (o1->oi_oid != o2->oi_oid || o1->oi_int4 != o2->oi_int4));
}
int oidint4cmp(OidInt4 o1, OidInt4 o2)
{
if (oidint4lt(o1, o2))
return (-1);
else if (oidint4eq(o1, o2))
return (0);
else
return (1);
}
OidInt4 mkoidint4(Oid v_oid, uint32 v_int4)
{
OidInt4 o;
o = (OidInt4) palloc(sizeof(OidInt4Data));
o->oi_oid = v_oid;
o->oi_int4 = v_int4;
return (o);
}

View File

@@ -0,0 +1,123 @@
/*-------------------------------------------------------------------------
*
* oidname.c--
* adt for multiple key indices involving oid and name. Used for cache
* index scans (could also be used in the general case with name).
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/oidname.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include "postgres.h"
#include "utils/oidcompos.h" /* where function declarations go */
#include "utils/builtins.h" /* for pg_atoi() */
#include "utils/elog.h"
#include "utils/palloc.h"
OidName
oidnamein(char *inStr)
{
OidName oc;
char *inptr;
oc = (OidName) palloc(sizeof(OidNameData));
memset(oc, 0, sizeof(OidNameData));
for (inptr = inStr; *inptr && *inptr != ','; inptr++)
;
if (*inptr) {
oc->id = (Oid) pg_atoi(inStr, sizeof(Oid), ',');
/* copy one less to ensure null-padding */
strncpy(oc->name.data,++inptr,NAMEDATALEN-1);
/* namestrcpy(&oc->name, ++inptr); */
}else
elog(WARN, "Bad input data for type oidname");
return oc;
}
char *
oidnameout(OidName oidname)
{
char buf[30+NAMEDATALEN]; /* oidname length + oid length + some safety */
char *res;
sprintf(buf, "%d,%s", oidname->id, oidname->name.data);
res = pstrdup(buf);
return(res);
}
bool
oidnamelt(OidName o1, OidName o2)
{
return (bool)
(o1->id < o2->id ||
(o1->id == o2->id && namecmp(&o1->name, &o2->name) < 0));
}
bool
oidnamele(OidName o1, OidName o2)
{
return (bool)
(o1->id < o2->id ||
(o1->id == o2->id && namecmp(&o1->name,&o2->name) <= 0));
}
bool
oidnameeq(OidName o1, OidName o2)
{
return (bool)
(o1->id == o2->id &&
(namecmp(&o1->name, &o2->name) == 0));
}
bool
oidnamene(OidName o1, OidName o2)
{
return (bool)
(o1->id != o2->id ||
(namecmp(&o1->name,&o2->name) != 0));
}
bool
oidnamege(OidName o1, OidName o2)
{
return (bool) (o1->id > o2->id || (o1->id == o2->id &&
namecmp(&o1->name, &o2->name) >= 0));
}
bool
oidnamegt(OidName o1, OidName o2)
{
return (bool) (o1->id > o2->id || (o1->id == o2->id &&
namecmp(&o1->name, &o2->name) > 0));
}
int
oidnamecmp(OidName o1, OidName o2)
{
if (o1->id == o2->id)
return (namecmp(&o1->name,&o2->name));
return (o1->id < o2->id) ? -1 : 1;
}
OidName
mkoidname(Oid id, char *name)
{
OidName oidname;
oidname = (OidName) palloc(sizeof(Oid)+NAMEDATALEN);
oidname->id = id;
namestrcpy(&oidname->name,name);
return oidname;
}

View File

@@ -0,0 +1,343 @@
/*-------------------------------------------------------------------------
*
* regexp.c--
* regular expression handling code.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
* Alistair Crooks added the code for the regex caching
* agc - cached the regular expressions used - there's a good chance
* that we'll get a hit, so this saves a compile step for every
* attempted match. I haven't actually measured the speed improvement,
* but it `looks' a lot quicker visually when watching regression
* test output.
*
* agc - incorporated Keith Bostic's Berkeley regex code into
* the tree for all ports. To distinguish this regex code from any that
* is existent on a platform, I've prepended the string "pg95_" to
* the functions regcomp, regerror, regexec and regfree.
* Fixed a bug that was originally a typo by me, where `i' was used
* instead of `oldest' when compiling regular expressions - benign
* results mostly, although occasionally it bit you...
*
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h" /* postgres system include file */
#include "utils/elog.h" /* for logging postgres errors */
#include "utils/palloc.h"
#include "utils/builtins.h" /* where the function declarations go */
#if defined(DISABLE_XOPEN_NLS)
#undef _XOPEN_SOURCE
#endif /* DISABLE_XOPEN_NLS */
#ifndef WIN32
#include <sys/types.h>
#include <regex.h>
#endif /* WIN32 why is this necessary? */
/* this is the number of cached regular expressions held. */
#ifndef MAX_CACHED_RES
#define MAX_CACHED_RES 32
#endif
/* this structure describes a cached regular expression */
struct cached_re_str {
struct varlena *cre_text; /* pattern as a text* */
char *cre_s; /* pattern as null-terminated string */
int cre_type; /* compiled-type: extended,icase etc */
regex_t cre_re; /* the compiled regular expression */
unsigned long cre_lru; /* lru tag */
};
static int rec = 0; /* # of cached re's */
static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */
static unsigned long lru; /* system lru tag */
/* attempt to compile `re' as an re, then match it against text */
/* cflags - flag to regcomp indicates case sensitivity */
static int
RE_compile_and_execute(struct varlena *text_re, char *text, int cflags)
{
int oldest;
int n;
int i;
char *re;
int regcomp_result;
re = textout(text_re);
/* find a previously compiled regular expression */
for (i = 0 ; i < rec ; i++) {
if (rev[i].cre_s) {
if (strcmp(rev[i].cre_s, re) == 0) {
if (rev[i].cre_type == cflags) {
rev[i].cre_lru = ++lru;
pfree(re);
return(pg95_regexec(&rev[i].cre_re,
text, 0,
(regmatch_t *) NULL, 0) == 0);
}
}
}
}
/* we didn't find it - make room in the cache for it */
if (rec == MAX_CACHED_RES) {
/* cache is full - find the oldest entry */
for (oldest = 0, i = 1 ; i < rec ; i++) {
if (rev[i].cre_lru < rev[oldest].cre_lru) {
oldest = i;
}
}
} else {
oldest = rec++;
}
/* if there was an old re, then de-allocate the space it used */
if (rev[oldest].cre_s != (char *) NULL) {
for (lru = i = 0 ; i < rec ; i++) {
rev[i].cre_lru =
(rev[i].cre_lru - rev[oldest].cre_lru) / 2;
if (rev[i].cre_lru > lru) {
lru = rev[i].cre_lru;
}
}
pg95_regfree(&rev[oldest].cre_re);
/* use malloc/free for the cre_s field because the storage
has to persist across transactions */
free(rev[oldest].cre_s);
}
/* compile the re */
regcomp_result = pg95_regcomp(&rev[oldest].cre_re, re, cflags);
if ( regcomp_result == 0) {
n = strlen(re);
/* use malloc/free for the cre_s field because the storage
has to persist across transactions */
rev[oldest].cre_s = (char *) malloc(n + 1);
(void) memmove(rev[oldest].cre_s, re, n);
rev[oldest].cre_s[n] = 0;
rev[oldest].cre_text = text_re;
rev[oldest].cre_lru = ++lru;
rev[oldest].cre_type = cflags;
pfree(re);
/* agc - fixed an old typo here */
return(pg95_regexec(&rev[oldest].cre_re, text, 0,
(regmatch_t *) NULL, 0) == 0);
} else {
char errMsg[1000];
/* re didn't compile */
rev[oldest].cre_s = (char *) NULL;
pg95_regerror(regcomp_result, &rev[oldest].cre_re, errMsg,
sizeof(errMsg));
elog(WARN,"regcomp failed with error %s",errMsg);
}
/* not reached */
return(0);
}
/*
* interface routines called by the function manager
*/
/*
fixedlen_regexeq:
a generic fixed length regexp routine
s - the string to match against (not necessarily null-terminated)
p - the pattern
charlen - the length of the string
*/
static bool
fixedlen_regexeq(char *s, struct varlena* p, int charlen, int cflags)
{
char *sterm;
int result;
if (!s || !p)
return FALSE;
/* be sure sterm is null-terminated */
sterm = (char *) palloc(charlen + 1);
memset(sterm, 0, charlen + 1);
strncpy(sterm, s, charlen);
result = RE_compile_and_execute(p, sterm, cflags);
pfree(sterm);
return ((bool) result);
}
/*
* routines that use the regexp stuff
*/
bool
char2regexeq(uint16 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_regexeq(s, p, 2, REG_EXTENDED));
}
bool
char2regexne(uint16 arg1, struct varlena *p)
{
return (!char2regexeq(arg1, p));
}
bool
char4regexeq(uint32 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_regexeq(s, p, 4, REG_EXTENDED));
}
bool
char4regexne(uint32 arg1, struct varlena *p)
{
return (!char4regexeq(arg1, p));
}
bool
char8regexeq(char *s, struct varlena *p)
{
return (fixedlen_regexeq(s, p, 8, REG_EXTENDED));
}
bool
char8regexne(char *s, struct varlena *p)
{
return (!char8regexeq(s, p));
}
bool
char16regexeq(char *s, struct varlena *p)
{
return (fixedlen_regexeq(s, p, 16, REG_EXTENDED));
}
bool
char16regexne(char *s, struct varlena *p)
{
return (!char16regexeq(s, p));
}
bool
nameregexeq(NameData *n, struct varlena *p)
{
return (fixedlen_regexeq(n->data, p, NAMEDATALEN, REG_EXTENDED));
}
bool
nameregexne(NameData *s, struct varlena *p)
{
return (!nameregexeq(s, p));
}
bool
textregexeq(struct varlena *s, struct varlena *p)
{
return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ, REG_EXTENDED));
}
bool
textregexne(struct varlena *s, struct varlena *p)
{
return (!textregexeq(s, p));
}
/*
* routines that use the regexp stuff, but ignore the case.
* for this, we use the REG_ICASE flag to pg95_regcomp
*/
bool
char2icregexeq(uint16 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_regexeq(s, p, 2, REG_ICASE | REG_EXTENDED));
}
bool
char2icregexne(uint16 arg1, struct varlena *p)
{
return (!char2icregexeq(arg1, p));
}
bool
char4icregexeq(uint32 arg1, struct varlena *p)
{
char *s = (char *) &arg1;
return (fixedlen_regexeq(s, p, 4, REG_ICASE | REG_EXTENDED ));
}
bool
char4icregexne(uint32 arg1, struct varlena *p)
{
return (!char4icregexeq(arg1, p));
}
bool
char8icregexeq(char *s, struct varlena *p)
{
return (fixedlen_regexeq(s, p, 8, REG_ICASE | REG_EXTENDED));
}
bool
char8icregexne(char *s, struct varlena *p)
{
return (!char8icregexeq(s, p));
}
bool
char16icregexeq(char *s, struct varlena *p)
{
return (fixedlen_regexeq(s, p, 16, REG_ICASE | REG_EXTENDED));
}
bool
char16icregexne(char *s, struct varlena *p)
{
return (!char16icregexeq(s, p));
}
bool
texticregexeq(struct varlena *s, struct varlena *p)
{
return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ,
REG_ICASE | REG_EXTENDED));
}
bool
texticregexne(struct varlena *s, struct varlena *p)
{
return (!texticregexeq(s, p));
}
bool
nameicregexeq(NameData *n, struct varlena *p)
{
return (fixedlen_regexeq(n->data, p, NAMEDATALEN,
REG_ICASE | REG_EXTENDED));
}
bool
nameicregexne(NameData *s, struct varlena *p)
{
return (!nameicregexeq(s, p));
}

View File

@@ -0,0 +1,159 @@
/*-------------------------------------------------------------------------
*
* regproc.c--
* Functions for the built-in type "RegProcedure".
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/regproc.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <string.h>
#include "postgres.h"
#include "access/heapam.h"
#include "access/relscan.h"
#include "access/skey.h"
#include "utils/tqual.h" /* for NowTimeQual */
#include "fmgr.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "catalog/catname.h"
#include "utils/builtins.h" /* where function declarations go */
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
/*
* regprocin - converts "proname" to proid
*
* proid of NULL signifies unknown
*/
int32 regprocin(char *proname)
{
Relation proc;
HeapScanDesc procscan;
HeapTuple proctup;
ScanKeyData key;
RegProcedure result;
bool isnull;
if (proname == NULL)
return(0);
proc = heap_openr(ProcedureRelationName);
if (!RelationIsValid(proc)) {
elog(WARN, "regprocin: could not open %s",
ProcedureRelationName);
return(0);
}
ScanKeyEntryInitialize(&key,
(bits16)0,
(AttrNumber)1,
(RegProcedure)F_CHAR16EQ,
(Datum)proname);
procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
if (!HeapScanIsValid(procscan)) {
heap_close(proc);
elog(WARN, "regprocin: could not being scan of %s",
ProcedureRelationName);
return(0);
}
proctup = heap_getnext(procscan, 0, (Buffer *) NULL);
switch (HeapTupleIsValid(proctup)) {
case 1:
result = (RegProcedure) heap_getattr(proctup,
InvalidBuffer,
ObjectIdAttributeNumber,
RelationGetTupleDescriptor(proc),
&isnull);
if (isnull) {
elog(FATAL, "regprocin: null procedure %s", proname);
}
break;
case 0:
result = (RegProcedure) 0;
#ifdef EBUG
elog(DEBUG, "regprocin: no such procedure %s", proname);
#endif /* defined(EBUG) */
}
heap_endscan(procscan);
heap_close(proc);
return((int32) result);
}
/*
* regprocout - converts proid to "proname"
*/
char *regprocout(RegProcedure proid)
{
Relation proc;
HeapScanDesc procscan;
HeapTuple proctup;
char *result;
ScanKeyData key;
result = (char *)palloc(NAMEDATALEN);
proc = heap_openr(ProcedureRelationName);
if (!RelationIsValid(proc)) {
elog(WARN, "regprocout: could not open %s",
ProcedureRelationName);
return(0);
}
ScanKeyEntryInitialize(&key,
(bits16)0,
(AttrNumber)ObjectIdAttributeNumber,
(RegProcedure)F_INT4EQ,
(Datum)proid);
procscan = heap_beginscan(proc, 0, NowTimeQual, 1, &key);
if (!HeapScanIsValid(procscan)) {
heap_close(proc);
elog(WARN, "regprocin: could not being scan of %s",
ProcedureRelationName);
return(0);
}
proctup = heap_getnext(procscan, 0, (Buffer *)NULL);
switch (HeapTupleIsValid(proctup)) {
char *s;
bool isnull;
case 1:
s = (char *) heap_getattr(proctup, InvalidBuffer, 1,
RelationGetTupleDescriptor(proc), &isnull);
if (!isnull) {
strncpy(result, s, 16);
break;
}
elog(FATAL, "regprocout: null procedure %d", proid);
/*FALLTHROUGH*/
case 0:
memset(result, 0, 16);
result[0] = '-';
#ifdef EBUG
elog(DEBUG, "regprocout: no such procedure %d", proid);
#endif /* defined(EBUG) */
}
heap_endscan(procscan);
heap_close(proc);
return(result);
}
/*****************************************************************************
* PUBLIC ROUTINES *
*****************************************************************************/
Oid RegprocToOid(RegProcedure rp)
{
return (Oid)rp;
}
/* (see int.c for comparison/operation routines) */
/* ========== PRIVATE ROUTINES ========== */

View File

@@ -0,0 +1,585 @@
/*-------------------------------------------------------------------------
*
* selfuncs.c--
* Selectivity functions for system catalogs and builtin types
*
* These routines are registered in the operator catalog in the
* "oprrest" and "oprjoin" attributes.
*
* XXX check all the functions--I suspect them to be 1-based.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h>
#include <string.h>
#include "access/heapam.h"
#include "utils/tqual.h" /* for NowTimeQual */
#include "fmgr.h"
#include "utils/builtins.h" /* for textout() prototype
and where the declarations go */
#include "utils/elog.h"
#include "utils/palloc.h"
#include "catalog/catname.h"
#include "utils/syscache.h"
#include "utils/lsyscache.h" /* for get_oprrest() */
#include "catalog/pg_statistic.h"
/* N is not a valid var/constant or relation id */
#define NONVALUE(N) ((N) == -1)
/*
* generalize the test for functional index selectivity request
*/
#define FunctionalSelectivity(nIndKeys,attNum) (attNum==InvalidAttrNumber)
static int32 getattnvals(Oid relid, AttrNumber attnum);
static void gethilokey(Oid relid, AttrNumber attnum, Oid opid,
char **high, char **low);
/*
* eqsel - Selectivity of "=" for any data type.
*/
float64
eqsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
int32 nvals;
float64 result;
result = (float64) palloc(sizeof(float64data));
if (NONVALUE(attno) || NONVALUE(relid))
*result = 0.1;
else {
nvals = getattnvals(relid, (int) attno);
if (nvals == 0)
*result = 0.0;
else
*result = 1.0 / nvals;
}
return(result);
}
/*
* neqsel - Selectivity of "!=" for any data type.
*/
float64
neqsel(Oid opid,
Oid relid,
AttrNumber attno,
char *value,
int32 flag)
{
float64 result;
result = eqsel(opid, relid, attno, value, flag);
*result = 1.0 - *result;
return(result);
}
/*
* intltsel - Selectivity of "<" for integers.
* Should work for both longs and shorts.
*/
float64
intltsel(Oid opid,
Oid relid,
AttrNumber attno,
int32 value,
int32 flag)
{
float64 result;
char *highchar, *lowchar;
long val, high, low, top, bottom;
result = (float64) palloc(sizeof(float64data));
if (NONVALUE(attno) || NONVALUE(relid))
*result = 1.0 / 3;
else {
/* XXX val = atol(value);*/
val = value;
gethilokey(relid, (int) attno, opid, &highchar, &lowchar);
if (*highchar == 'n' || *lowchar == 'n') {
*result = 1.0/3.0;
return (result);
}
high = atol(highchar);
low = atol(lowchar);
if ((flag & SEL_RIGHT && val < low) ||
(!(flag & SEL_RIGHT) && val > high)) {
int nvals;
nvals = getattnvals(relid, (int) attno);
if (nvals == 0)
*result = 1.0 / 3.0;
else
*result = 3.0 / nvals;
}else {
bottom = high - low;
if (bottom == 0)
++bottom;
if (flag & SEL_RIGHT)
top = val - low;
else
top = high - val;
if (top > bottom)
*result = 1.0;
else {
if (top == 0)
++top;
*result = ((1.0 * top) / bottom);
}
}
}
return(result);
}
/*
* intgtsel - Selectivity of ">" for integers.
* Should work for both longs and shorts.
*/
float64
intgtsel(Oid opid,
Oid relid,
AttrNumber attno,
int32 value,
int32 flag)
{
float64 result;
int notflag;
if (flag & 0)
notflag = flag & ~SEL_RIGHT;
else
notflag = flag | SEL_RIGHT;
result = intltsel(opid, relid, attno, value, (int32) notflag);
return(result);
}
/*
* eqjoinsel - Join selectivity of "="
*/
float64
eqjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
int32 num1, num2, max;
result = (float64) palloc(sizeof(float64data));
if (NONVALUE(attno1) || NONVALUE(relid1) ||
NONVALUE(attno2) || NONVALUE(relid2))
*result = 0.1;
else {
num1 = getattnvals(relid1, (int) attno1);
num2 = getattnvals(relid2, (int) attno2);
max = (num1 > num2) ? num1 : num2;
if (max == 0)
*result = 1.0;
else
*result = 1.0 / max;
}
return(result);
}
/*
* neqjoinsel - Join selectivity of "!="
*/
float64
neqjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
result = eqjoinsel(opid, relid1, attno1, relid2, attno2);
*result = 1.0 - *result;
return(result);
}
/*
* intltjoinsel - Join selectivity of "<"
*/
float64
intltjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 3.0;
return(result);
}
/*
* intgtjoinsel - Join selectivity of ">"
*/
float64
intgtjoinsel(Oid opid,
Oid relid1,
AttrNumber attno1,
Oid relid2,
AttrNumber attno2)
{
float64 result;
result = (float64) palloc(sizeof(float64data));
*result = 1.0 / 3.0;
return(result);
}
/*
* getattnvals - Retrieves the number of values within an attribute.
*
* Note:
* getattnvals and gethilokey both currently use keyed
* relation scans and amgetattr. Alternatively,
* the relation scan could be non-keyed and the tuple
* returned could be cast (struct X *) tuple + tuple->t_hoff.
* The first method is good for testing the implementation,
* but the second may ultimately be faster?!? In any case,
* using the cast instead of amgetattr would be
* more efficient. However, the cast will not work
* for gethilokey which accesses stahikey in struct statistic.
*/
static int32
getattnvals(Oid relid, AttrNumber attnum)
{
HeapTuple atp;
int nvals;
atp = SearchSysCacheTuple(ATTNUM,
ObjectIdGetDatum(relid),
Int16GetDatum(attnum),
0,0);
if (!HeapTupleIsValid(atp)) {
elog(WARN, "getattnvals: no attribute tuple %d %d",
relid, attnum);
return(0);
}
nvals = ((AttributeTupleForm ) GETSTRUCT(atp))->attnvals;
if (nvals > 0) return(nvals);
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(relid),
0,0,0);
/* XXX -- use number of tuples as number of distinctive values
just for now, in case number of distinctive values is
not cached */
if (!HeapTupleIsValid(atp)) {
elog(WARN, "getattnvals: no relation tuple %d", relid);
return(0);
}
nvals = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
return(nvals);
}
/*
* gethilokey - Returns a pointer to strings containing
* the high and low keys within an attribute.
*
* Currently returns "0", and "0" in high and low if the statistic
* catalog does not contain the proper tuple. Eventually, the
* statistic demon should have the tuple maintained, and it should
* elog() if the tuple is missing.
*
* XXX Question: is this worth sticking in the catalog caches,
* or will this get invalidated too often?
*/
static void
gethilokey(Oid relid,
AttrNumber attnum,
Oid opid,
char **high,
char **low)
{
register Relation rdesc;
register HeapScanDesc sdesc;
static ScanKeyData key[3] = {
{ 0, Anum_pg_statistic_starelid, F_OIDEQ },
{ 0, Anum_pg_statistic_staattnum, F_INT2EQ },
{ 0, Anum_pg_statistic_staop, F_OIDEQ }
};
bool isnull;
HeapTuple tuple;
rdesc = heap_openr(StatisticRelationName);
key[0].sk_argument = ObjectIdGetDatum(relid);
key[1].sk_argument = Int16GetDatum((int16) attnum);
key[2].sk_argument = ObjectIdGetDatum(opid);
sdesc = heap_beginscan(rdesc, 0, NowTimeQual, 3, key);
tuple = heap_getnext(sdesc, 0, (Buffer *) NULL);
if (!HeapTupleIsValid(tuple)) {
*high = "n";
*low = "n";
/* XXX elog(WARN, "gethilokey: statistic tuple not found");*/
return;
}
*high = textout((struct varlena *)
heap_getattr(tuple,
InvalidBuffer,
Anum_pg_statistic_stahikey,
RelationGetTupleDescriptor(rdesc),
&isnull));
if (isnull)
elog(DEBUG, "gethilokey: high key is null");
*low = textout((struct varlena *)
heap_getattr(tuple,
InvalidBuffer,
Anum_pg_statistic_stalokey,
RelationGetTupleDescriptor(rdesc),
&isnull));
if (isnull)
elog(DEBUG, "gethilokey: low key is null");
heap_endscan(sdesc);
heap_close(rdesc);
}
float64
btreesel(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
float64 result;
float64data resultData;
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
/*
* Need to call the functions selectivity
* function here. For now simply assume it's
* 1/3 since functions don't currently
* have selectivity functions
*/
resultData = 1.0 / 3.0;
result = &resultData;
}
else {
result = (float64)fmgr(get_oprrest (operatorObjectId),
(char*)operatorObjectId,
(char*)indrelid,
(char*)attributeNumber,
(char*)constValue,
(char*)constFlag,
NULL);
}
if (!PointerIsValid(result))
elog(WARN, "Btree Selectivity: bad pointer");
if (*result < 0.0 || *result > 1.0)
elog(WARN, "Btree Selectivity: bad value %lf", *result);
return(result);
}
float64
btreenpage(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
float64 temp, result;
float64data tempData;
HeapTuple atp;
int npage;
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
/*
* Need to call the functions selectivity
* function here. For now simply assume it's
* 1/3 since functions don't currently
* have selectivity functions
*/
tempData = 1.0 / 3.0;
temp = &tempData;
}
else {
temp = (float64)fmgr(get_oprrest (operatorObjectId),
(char*)operatorObjectId,
(char*)indrelid,
(char*)attributeNumber,
(char*)constValue,
(char*)constFlag,
NULL);
}
atp = SearchSysCacheTuple(RELOID,
ObjectIdGetDatum(indexrelid),
0,0,0);
if (!HeapTupleIsValid(atp)) {
elog(WARN, "btreenpage: no index tuple %d", indexrelid);
return(0);
}
npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
result = (float64)palloc(sizeof(float64data));
*result = *temp * npage;
return(result);
}
float64
hashsel(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
float64 result;
float64data resultData;
HeapTuple atp;
int ntuples;
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
/*
* Need to call the functions selectivity
* function here. For now simply use 1/Number of Tuples
* since functions don't currently
* have selectivity functions
*/
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
0,0,0);
if (!HeapTupleIsValid(atp)) {
elog(WARN, "hashsel: no index tuple %d", indexrelid);
return(0);
}
ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
if (ntuples > 0) {
resultData = 1.0 / (float64data) ntuples;
}
else {
resultData = (float64data) (1.0 / 100.0);
}
result = &resultData;
}
else {
result = (float64)fmgr(get_oprrest (operatorObjectId),
(char*)operatorObjectId,
(char*)indrelid,
(char*)attributeNumber,
(char*)constValue,
(char*)constFlag,
NULL);
}
if (!PointerIsValid(result))
elog(WARN, "Hash Table Selectivity: bad pointer");
if (*result < 0.0 || *result > 1.0)
elog(WARN, "Hash Table Selectivity: bad value %lf", *result);
return(result);
}
float64
hashnpage(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
float64 temp, result;
float64data tempData;
HeapTuple atp;
int npage;
int ntuples;
atp = SearchSysCacheTuple(RELOID, ObjectIdGetDatum(indexrelid),
0,0,0);
if (!HeapTupleIsValid(atp)) {
elog(WARN, "hashsel: no index tuple %d", indexrelid);
return(0);
}
if (FunctionalSelectivity(nIndexKeys, attributeNumber)) {
/*
* Need to call the functions selectivity
* function here. For now, use 1/Number of Tuples
* since functions don't currently
* have selectivity functions
*/
ntuples = ((Form_pg_class) GETSTRUCT(atp))->reltuples;
if (ntuples > 0) {
tempData = 1.0 / (float64data) ntuples;
}
else {
tempData = (float64data) (1.0 / 100.0);
}
temp = &tempData;
}
else {
temp = (float64)fmgr(get_oprrest (operatorObjectId),
(char*)operatorObjectId,
(char*)indrelid,
(char*)attributeNumber,
(char*)constValue,
(char*)constFlag,
NULL);
}
npage = ((Form_pg_class) GETSTRUCT(atp))->relpages;
result = (float64)palloc(sizeof(float64data));
*result = *temp * npage;
return(result);
}
float64
rtsel(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
return (btreesel(operatorObjectId, indrelid, attributeNumber,
constValue, constFlag, nIndexKeys, indexrelid));
}
float64
rtnpage(Oid operatorObjectId,
Oid indrelid,
AttrNumber attributeNumber,
char *constValue,
int32 constFlag,
int32 nIndexKeys,
Oid indexrelid)
{
return (btreenpage(operatorObjectId, indrelid, attributeNumber,
constValue, constFlag, nIndexKeys, indexrelid));
}

View File

@@ -0,0 +1,164 @@
/*-------------------------------------------------------------------------
*
* sets.c--
* Functions for sets, which are defined by queries.
* Example: a set is defined as being the result of the query
* retrieve (X.all)
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include "postgres.h"
#include "utils/elog.h"
#include "nodes/pg_list.h" /* for LispValue and List */
#include "access/htup.h" /* for HeapTuple */
#include "access/heapam.h"
#include "access/relscan.h"
#include "access/xact.h"
#include "catalog/pg_proc.h" /* for Form_pg_proc */
#include "utils/syscache.h" /* for PROOID */
#include "catalog/catname.h" /* for ProcedureRelationName */
#include "catalog/indexing.h" /* for Num_pg_proc_indices */
#include "storage/lmgr.h"
#include "utils/sets.h" /* for GENERICSETNAME */
#include "tcop/dest.h"
#include "fmgr.h"
extern CommandDest whereToSendOutput; /* defined in tcop/postgres.c */
/*
* SetDefine - converts query string defining set to an oid
*
* The query string is used to store the set as a function in
* pg_proc. The name of the function is then changed to use the
* OID of its tuple in pg_proc.
*/
Oid
SetDefine(char *querystr, char *typename)
{
Oid setoid;
char *procname = GENERICSETNAME;
char *fileName = "-";
char realprocname[16];
HeapTuple tup, newtup;
Form_pg_proc proc;
Relation procrel;
int i;
Datum replValue[Natts_pg_proc];
char replNull[Natts_pg_proc];
char repl[Natts_pg_proc];
HeapScanDesc pg_proc_scan;
Buffer buffer;
ItemPointerData ipdata;
static ScanKeyData oidKey[1] = {
{ 0, ObjectIdAttributeNumber, ObjectIdEqualRegProcedure }};
setoid = ProcedureCreate(procname, /* changed below, after oid known */
true, /* returnsSet */
typename, /* returnTypeName */
"sql", /* languageName */
querystr, /* sourceCode */
fileName, /* fileName */
false, /* canCache */
true, /* trusted */
100, /* byte_pct */
0, /* perbyte_cpu */
0, /* percall_cpu */
100, /* outin_ratio */
NIL, /* argList */
whereToSendOutput);
/* Since we're still inside this command of the transaction, we can't
* see the results of the procedure definition unless we pretend
* we've started the next command. (Postgres's solution to the
* Halloween problem is to not allow you to see the results of your
* command until you start the next command.)
*/
CommandCounterIncrement();
tup = SearchSysCacheTuple(PROOID,
ObjectIdGetDatum(setoid),
0,0,0);
if (!HeapTupleIsValid(tup))
elog(WARN, "setin: unable to define set %s", querystr);
/* We can tell whether the set was already defined by checking
* the name. If it's GENERICSETNAME, the set is new. If it's
* "set<some oid>" it's already defined.
*/
proc = (Form_pg_proc)GETSTRUCT(tup);
if (!strcmp((char*)procname, (char*)&(proc->proname))) {
/* make the real proc name */
sprintf(realprocname, "set%u", setoid);
/* set up the attributes to be modified or kept the same */
repl[0] = 'r';
for (i = 1; i < Natts_pg_proc; i++) repl[i] = ' ';
replValue[0] = (Datum)realprocname;
for (i = 1; i < Natts_pg_proc; i++) replValue[i] = (Datum)0;
for (i = 0; i < Natts_pg_proc; i++) replNull[i] = ' ';
/* change the pg_proc tuple */
procrel = heap_openr(ProcedureRelationName);
RelationSetLockForWrite(procrel);
fmgr_info(ObjectIdEqualRegProcedure,
&oidKey[0].sk_func,
&oidKey[0].sk_nargs);
oidKey[0].sk_argument = ObjectIdGetDatum(setoid);
pg_proc_scan = heap_beginscan(procrel,
0,
SelfTimeQual,
1,
oidKey);
tup = heap_getnext(pg_proc_scan, 0, &buffer);
if (HeapTupleIsValid(tup)) {
newtup = heap_modifytuple(tup,
buffer,
procrel,
replValue,
replNull,
repl);
/* XXX may not be necessary */
ItemPointerCopy(&tup->t_ctid, &ipdata);
setheapoverride(true);
(void) heap_replace(procrel, &ipdata, newtup);
setheapoverride(false);
setoid = newtup->t_oid;
} else
elog(WARN, "setin: could not find new set oid tuple");
heap_endscan(pg_proc_scan);
if (RelationGetRelationTupleForm(procrel)->relhasindex)
{
Relation idescs[Num_pg_proc_indices];
CatalogOpenIndices(Num_pg_proc_indices, Name_pg_proc_indices, idescs);
CatalogIndexInsert(idescs, Num_pg_proc_indices, procrel, newtup);
CatalogCloseIndices(Num_pg_proc_indices, idescs);
}
RelationUnsetLockForWrite(procrel);
heap_close(procrel);
}
return setoid;
}
/* This function is a placeholder. The parser uses the OID of this
* function to fill in the :funcid field of a set. This routine is
* never executed. At runtime, the OID of the actual set is substituted
* into the :funcid.
*/
int
seteval(Oid funcoid)
{
return 17;
}

View File

@@ -0,0 +1,92 @@
/*-------------------------------------------------------------------------
*
* tid.c--
* Functions for the built-in type tuple id
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/tid.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
* NOTES
* input routine largely stolen from boxin().
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "storage/block.h"
#include "storage/off.h"
#include "storage/itemptr.h"
#include "storage/bufpage.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where function declarations go */
#define LDELIM '('
#define RDELIM ')'
#define DELIM ','
#define NTIDARGS 2
/* ----------------------------------------------------------------
* tidin
* ----------------------------------------------------------------
*/
ItemPointer
tidin(char *str)
{
char *p, *coord[NTIDARGS];
int i;
ItemPointer result;
BlockNumber blockNumber;
OffsetNumber offsetNumber;
if (str == NULL)
return NULL;
for (i = 0, p = str; *p && i < NTIDARGS && *p != RDELIM; p++)
if (*p == DELIM || (*p == LDELIM && !i))
coord[i++] = p + 1;
if (i < NTIDARGS - 1)
return NULL;
blockNumber = (BlockNumber) atoi(coord[0]);
offsetNumber = (OffsetNumber) atoi(coord[1]);
result = (ItemPointer) palloc(sizeof(ItemPointerData));
ItemPointerSet(result, blockNumber, offsetNumber);
return result;
}
/* ----------------------------------------------------------------
* tidout
* ----------------------------------------------------------------
*/
char *
tidout(ItemPointer itemPtr)
{
BlockNumber blockNumber;
OffsetNumber offsetNumber;
BlockId blockId;
char buf[32];
char *str;
blockId = &(itemPtr->ip_blkid);
blockNumber = BlockIdGetBlockNumber(blockId);
offsetNumber = itemPtr->ip_posid;
sprintf(buf, "(%d,%d)", blockNumber, offsetNumber);
str = (char *) palloc(strlen(buf)+1);
strcpy(str, buf);
return str;
}

View File

@@ -0,0 +1,496 @@
/*-------------------------------------------------------------------------
*
* char.c--
* Functions for the built-in type char() and varchar().
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <stdio.h> /* for sprintf() */
#include <string.h>
#include "postgres.h"
#include "utils/palloc.h"
#include "utils/elog.h"
/*
* CHAR() and VARCHAR() types are part of the ANSI SQL standard. CHAR()
* is for blank-padded string whose length is specified in CREATE TABLE.
* VARCHAR is for storing string whose length is at most the length specified
* at CREATE TABLE time.
*
* It's hard to implement these types because we cannot figure out what
* the length of the type from the type itself. I change (hopefully all) the
* fmgr calls that invoke input functions of a data type to supply the
* length also. (eg. in INSERTs, we have the tupleDescriptor which contains
* the length of the attributes and hence the exact length of the char() or
* varchar(). We pass this to bpcharin() or varcharin().) In the case where
* we cannot determine the length, we pass in -1 instead and the input string
* must be null-terminated.
*
* We actually implement this as a varlena so that we don't have to pass in
* the length for the comparison functions. (The difference between "text"
* is that we truncate and possibly blank-pad the string at insertion time.)
*
* - ay 6/95
*/
/*****************************************************************************
* bpchar - char() *
*****************************************************************************/
/*
* bpcharin -
* converts a string of char() type to the internal representation.
* len is the length specified in () plus 4 bytes. (XXX dummy is here
* because we pass typelem as the second argument for array_in.)
*/
char *
bpcharin(char *s, int dummy, int typlen)
{
char *result, *r;
int len = typlen - 4;
int i;
if (s == NULL)
return((char *) NULL);
if (typlen == -1) {
/*
* this is here because some functions can't supply the typlen
*/
len = strlen(s);
typlen = len + 4;
}
if (len < 1 || len > 4096)
elog(WARN, "bpcharin: length of char() must be between 1 and 4096");
result = (char *) palloc(typlen);
*(int32*)result = typlen;
r = result + 4;
for(i=0; i < len; i++, r++, s++) {
*r = *s;
if (*r == '\0')
break;
}
/* blank pad the string if necessary */
for(; i < len; i++) {
*r++ = ' ';
}
return(result);
}
char *
bpcharout(char *s)
{
char *result;
int len;
if (s == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
} else {
len = *(int32*)s - 4;
result = (char *) palloc(len+1);
strncpy(result, s+4, len); /* these are blank-padded */
result[len] = '\0';
}
return(result);
}
/*****************************************************************************
* varchar - varchar() *
*****************************************************************************/
/*
* vcharin -
* converts a string of varchar() type to the internal representation.
* len is the length specified in () plus 4 bytes. (XXX dummy is here
* because we pass typelem as the second argument for array_in.)
*/
char *
varcharin(char *s, int dummy, int typlen)
{
char *result;
int len = typlen - 4;
if (s == NULL)
return((char *) NULL);
if (typlen == -1) {
/*
* this is here because some functions can't supply the typlen
*/
len = strlen(s);
typlen = len + 4;
}
if (len < 1 || len > 4096)
elog(WARN, "bpcharin: length of char() must be between 1 and 4096");
result = (char *) palloc(typlen);
*(int32*)result = typlen;
memset(result+4, 0, len);
(void) strncpy(result+4, s, len);
return(result);
}
char *
varcharout(char *s)
{
char *result;
int len;
if (s == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
} else {
len = *(int32*)s - 4;
result = (char *) palloc(len+1);
memset(result, 0, len+1);
strncpy(result, s+4, len);
}
return(result);
}
/*****************************************************************************
* Comparison Functions used for bpchar
*****************************************************************************/
static int
bcTruelen(char *arg)
{
char *s = arg + 4;
int i;
int len;
len = *(int32*)arg - 4;
for(i=len-1; i >= 0; i--) {
if (s[i] != ' ')
break;
}
return (i+1);
}
int32
bpchareq(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
if (len1!=len2)
return 0;
return(strncmp(arg1+4, arg2+4, len1) == 0);
}
int32
bpcharne(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
if (len1!=len2)
return 1;
return(strncmp(arg1+4, arg2+4, len1) != 0);
}
int32
bpcharlt(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
if (cmp == 0)
return (len1<len2);
else
return (cmp < 0);
}
int32
bpcharle(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)) <= 0);
}
int32
bpchargt(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
if (cmp == 0)
return (len1 > len2);
else
return (cmp > 0);
}
int32
bpcharge(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)) >= 0);
}
int32
bpcharcmp(char *arg1, char *arg2)
{
int len1, len2;
len1 = bcTruelen(arg1);
len2 = bcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)));
}
/*****************************************************************************
* Comparison Functions used for varchar
*****************************************************************************/
static int
vcTruelen(char *arg)
{
char *s = arg + 4;
int i;
int len;
len = *(int32*)arg - 4;
for(i=0; i < len; i++) {
if (*s++ == '\0')
break;
}
return i;
}
int32
varchareq(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
if (len1!=len2)
return 0;
return(strncmp(arg1+4, arg2+4, len1) == 0);
}
int32
varcharne(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
if (len1!=len2)
return 1;
return(strncmp(arg1+4, arg2+4, len1) != 0);
}
int32
varcharlt(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
if (cmp == 0)
return (len1<len2);
else
return (cmp < 0);
}
int32
varcharle(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)) <= 0);
}
int32
varchargt(char *arg1, char *arg2)
{
int len1, len2;
int cmp;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
cmp = strncmp(arg1+4, arg2+4, Min(len1,len2));
if (cmp == 0)
return (len1 > len2);
else
return (cmp > 0);
}
int32
varcharge(char *arg1, char *arg2)
{
int len1, len2;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)) >= 0);
}
int32
varcharcmp(char *arg1, char *arg2)
{
int len1, len2;
len1 = vcTruelen(arg1);
len2 = vcTruelen(arg2);
return(strncmp(arg1+4, arg2+4, Min(len1,len2)));
}
/*****************************************************************************
* Hash functions (modified from hashtext in access/hash/hashfunc.c)
*****************************************************************************/
uint32 hashbpchar(struct varlena *key)
{
int keylen;
char *keydata;
uint32 n;
int loop;
keydata = VARDATA(key);
keylen = bcTruelen((char*)key);
#define HASHC n = *keydata++ + 65599 * n
n = 0;
if (keylen > 0) {
loop = (keylen + 8 - 1) >> 3;
switch (keylen & (8 - 1)) {
case 0:
do { /* All fall throughs */
HASHC;
case 7:
HASHC;
case 6:
HASHC;
case 5:
HASHC;
case 4:
HASHC;
case 3:
HASHC;
case 2:
HASHC;
case 1:
HASHC;
} while (--loop);
}
}
return (n);
}
uint32 hashvarchar(struct varlena *key)
{
int keylen;
char *keydata;
uint32 n;
int loop;
keydata = VARDATA(key);
keylen = vcTruelen((char*)key);
#define HASHC n = *keydata++ + 65599 * n
n = 0;
if (keylen > 0) {
loop = (keylen + 8 - 1) >> 3;
switch (keylen & (8 - 1)) {
case 0:
do { /* All fall throughs */
HASHC;
case 7:
HASHC;
case 6:
HASHC;
case 5:
HASHC;
case 4:
HASHC;
case 3:
HASHC;
case 2:
HASHC;
case 1:
HASHC;
} while (--loop);
}
}
return (n);
}

View File

@@ -0,0 +1,488 @@
/*-------------------------------------------------------------------------
*
* varlena.c--
* Functions for the variable-length built-in types.
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/utils/adt/varlena.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $
*
*-------------------------------------------------------------------------
*/
#include <ctype.h>
#include <string.h>
#include "postgres.h"
#include "utils/elog.h"
#include "utils/palloc.h"
#include "utils/builtins.h" /* where function declarations go */
/*****************************************************************************
* USER I/O ROUTINES *
*****************************************************************************/
#define VAL(CH) ((CH) - '0')
#define DIG(VAL) ((VAL) + '0')
/*
* byteain - converts from printable representation of byte array
*
* Non-printable characters must be passed as '\nnn' (octal) and are
* converted to internal form. '\' must be passed as '\\'.
* elog(WARN, ...) if bad form.
*
* BUGS:
* The input is scaned twice.
* The error checking of input is minimal.
*/
struct varlena *
byteain(char *inputText)
{
register char *tp;
register char *rp;
register int byte;
struct varlena *result;
if (inputText == NULL)
elog(WARN, "Bad input string for type bytea");
for (byte = 0, tp = inputText; *tp != '\0'; byte++)
if (*tp++ == '\\')
{
if (*tp == '\\')
tp++;
else if (!isdigit(*tp++) ||
!isdigit(*tp++) ||
!isdigit(*tp++))
elog(WARN, "Bad input string for type bytea");
}
tp = inputText;
byte += sizeof(int32); /* varlena? */
result = (struct varlena *) palloc(byte);
result->vl_len = byte; /* varlena? */
rp = result->vl_dat;
while (*tp != '\0')
if (*tp != '\\' || *++tp == '\\')
*rp++ = *tp++;
else {
byte = VAL(*tp++);
byte <<= 3;
byte += VAL(*tp++);
byte <<= 3;
*rp++ = byte + VAL(*tp++);
}
return(result);
}
/*
* Shoves a bunch of memory pointed at by bytes into varlena.
* BUGS: Extremely unportable as things shoved can be string
* representations of structs, etc.
*/
struct varlena *
shove_bytes(unsigned char *stuff, int len)
{
struct varlena *result;
result = (struct varlena *) palloc(len + sizeof(int32));
result->vl_len = len;
memmove(result->vl_dat,
stuff + sizeof(int32),
len - sizeof(int32));
return(result);
}
/*
* byteaout - converts to printable representation of byte array
*
* Non-printable characters are inserted as '\nnn' (octal) and '\' as
* '\\'.
*
* NULL vlena should be an error--returning string with NULL for now.
*/
char *
byteaout(struct varlena *vlena)
{
register char *vp;
register char *rp;
register int val; /* holds unprintable chars */
int i;
int len;
static char *result;
if (vlena == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
return(result);
}
vp = vlena->vl_dat;
len = 1; /* empty string has 1 char */
for (i = vlena->vl_len - sizeof(int32); i != 0; i--, vp++) /* varlena? */
if (*vp == '\\')
len += 2;
else if (isascii(*vp) && isprint(*vp))
len++;
else
len += 4;
rp = result = (char *) palloc(len);
vp = vlena->vl_dat;
for (i = vlena->vl_len - sizeof(int32); i != 0; i--) /* varlena? */
if (*vp == '\\') {
*vp++;
*rp++ = '\\';
*rp++ = '\\';
} else if (isascii(*vp) && isprint(*vp))
*rp++ = *vp++;
else {
val = *vp++;
*rp = '\\';
rp += 3;
*rp-- = DIG(val & 07);
val >>= 3;
*rp-- = DIG(val & 07);
val >>= 3;
*rp = DIG(val & 03);
rp += 3;
}
*rp = '\0';
return(result);
}
/*
* textin - converts "..." to internal representation
*/
struct varlena *
textin(char *inputText)
{
struct varlena *result;
int len;
if (inputText == NULL)
return(NULL);
len = strlen(inputText) + VARHDRSZ;
result = (struct varlena *) palloc(len);
VARSIZE(result) = len;
memmove(VARDATA(result), inputText, len - VARHDRSZ);
return(result);
}
/*
* textout - converts internal representation to "..."
*/
char *
textout(struct varlena *vlena)
{
int len;
char *result;
if (vlena == NULL) {
result = (char *) palloc(2);
result[0] = '-';
result[1] = '\0';
return(result);
}
len = VARSIZE(vlena) - VARHDRSZ;
result = (char *) palloc(len + 1);
memmove(result, VARDATA(vlena), len);
result[len] = '\0';
return(result);
}
/* ========== PUBLIC ROUTINES ========== */
/*
* textcat -
* takes two text* and returns a text* that is the concatentation of
* the two
*/
text*
textcat(text* t1, text* t2)
{
int newlen;
char *str1, *str2;
text* result;
if (t1 == NULL) return t2;
if (t2 == NULL) return t1;
/* since t1, and t2 are non-null, str1 and str2 must also be non-null */
str1 = textout(t1);
str2 = textout(t2);
/* we use strlen here to calculate the length because the size fields
of t1, t2 may be longer than necessary to hold the string */
newlen = strlen(str1) + strlen(str2) + VARHDRSZ;
result = (text*)palloc(newlen);
strcpy(VARDATA(result), str1);
strncat(VARDATA(result), str2, newlen - VARHDRSZ);
/* [TRH] Was:
strcat(VARDATA(result), str2);
which may corrupt the malloc arena due to writing trailing \0. */
pfree(str1);
pfree(str2);
return result;
}
/*
* texteq - returns 1 iff arguments are equal
* textne - returns 1 iff arguments are not equal
*/
int32
texteq(struct varlena *arg1, struct varlena *arg2)
{
register int len;
register char *a1p, *a2p;
if (arg1 == NULL || arg2 == NULL)
return((int32) NULL);
if ((len = arg1->vl_len) != arg2->vl_len)
return((int32) 0);
a1p = arg1->vl_dat;
a2p = arg2->vl_dat;
/*
* Varlenas are stored as the total size (data + size variable)
* followed by the data. The size variable is an int32 so the
* length of the data is the total length less sizeof(int32)
*/
len -= sizeof(int32);
while (len-- != 0)
if (*a1p++ != *a2p++)
return((int32) 0);
return((int32) 1);
}
int32
textne(struct varlena *arg1, struct varlena *arg2)
{
return((int32) !texteq(arg1, arg2));
}
int32
text_lt(struct varlena *arg1, struct varlena *arg2)
{
int len;
char *a1p, *a2p;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
a1p = VARDATA(arg1);
a2p = VARDATA(arg2);
if ((len = arg1->vl_len) > arg2->vl_len)
len = arg2->vl_len;
len -= sizeof(int32);
while (len != 0 && *a1p == *a2p)
{
a1p++;
a2p++;
len--;
}
if (len)
return (int32) (*a1p < *a2p);
else
return (int32) (arg1->vl_len < arg2->vl_len);
}
int32
text_le(struct varlena *arg1, struct varlena *arg2)
{
int len;
char *a1p, *a2p;
if (arg1 == NULL || arg2 == NULL)
return((int32) 0);
a1p = VARDATA(arg1);
a2p = VARDATA(arg2);
if ((len = arg1->vl_len) > arg2->vl_len)
len = arg2->vl_len;
len -= sizeof(int32); /* varlena! */
while (len != 0 && *a1p == *a2p)
{
a1p++;
a2p++;
len--;
}
if (len)
return (int32) (*a1p < *a2p);
else
return ((int32) VARSIZE(arg1) <= VARSIZE(arg2));
}
int32
text_gt(struct varlena *arg1, struct varlena *arg2)
{
return ((int32) !text_le(arg1, arg2));
}
int32
text_ge(struct varlena *arg1, struct varlena *arg2)
{
return ((int32) !text_lt(arg1, arg2));
}
/*-------------------------------------------------------------
* byteaGetSize
*
* get the number of bytes contained in an instance of type 'bytea'
*-------------------------------------------------------------
*/
int32
byteaGetSize(struct varlena *v)
{
register int len;
len = v->vl_len - sizeof(v->vl_len);
return(len);
}
/*-------------------------------------------------------------
* byteaGetByte
*
* this routine treats "bytea" as an array of bytes.
* It returns the Nth byte (a number between 0 and 255) or
* it dies if the length of this array is less than n.
*-------------------------------------------------------------
*/
int32
byteaGetByte(struct varlena *v, int32 n)
{
int len;
int byte;
len = byteaGetSize(v);
if (n>=len) {
elog(WARN, "byteaGetByte: index (=%d) out of range [0..%d]",
n,len-1);
}
byte = (unsigned char) (v->vl_dat[n]);
return((int32) byte);
}
/*-------------------------------------------------------------
* byteaGetBit
*
* This routine treats a "bytea" type like an array of bits.
* It returns the value of the Nth bit (0 or 1).
* If 'n' is out of range, it dies!
*
*-------------------------------------------------------------
*/
int32
byteaGetBit(struct varlena *v, int32 n)
{
int byteNo, bitNo;
int byte;
byteNo = n/8;
bitNo = n%8;
byte = byteaGetByte(v, byteNo);
if (byte & (1<<bitNo)) {
return((int32)1);
} else {
return((int32)0);
}
}
/*-------------------------------------------------------------
* byteaSetByte
*
* Given an instance of type 'bytea' creates a new one with
* the Nth byte set to the given value.
*
*-------------------------------------------------------------
*/
struct varlena *
byteaSetByte(struct varlena *v, int32 n, int32 newByte)
{
int len;
struct varlena *res;
len = byteaGetSize(v);
if (n>=len) {
elog(WARN,
"byteaSetByte: index (=%d) out of range [0..%d]",
n, len-1);
}
/*
* Make a copy of the original varlena.
*/
res = (struct varlena *) palloc(VARSIZE(v));
if (res==NULL) {
elog(WARN, "byteaSetByte: Out of memory (%d bytes requested)",
VARSIZE(v));
}
memmove((char *)res, (char *)v, VARSIZE(v));
/*
* Now set the byte.
*/
res->vl_dat[n] = newByte;
return(res);
}
/*-------------------------------------------------------------
* byteaSetBit
*
* Given an instance of type 'bytea' creates a new one with
* the Nth bit set to the given value.
*
*-------------------------------------------------------------
*/
struct varlena *
byteaSetBit(struct varlena *v, int32 n, int32 newBit)
{
struct varlena *res;
int oldByte, newByte;
int byteNo, bitNo;
/*
* sanity check!
*/
if (newBit != 0 && newBit != 1) {
elog(WARN, "byteaSetByte: new bit must be 0 or 1");
}
/*
* get the byte where the bit we want is stored.
*/
byteNo = n / 8;
bitNo = n % 8;
oldByte = byteaGetByte(v, byteNo);
/*
* calculate the new value for that byte
*/
if (newBit == 0) {
newByte = oldByte & (~(1<<bitNo));
} else {
newByte = oldByte | (1<<bitNo);
}
/*
* NOTE: 'byteaSetByte' creates a copy of 'v' & sets the byte.
*/
res = byteaSetByte(v, byteNo, newByte);
return(res);
}