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:
20
src/backend/utils/adt/Makefile.inc
Normal file
20
src/backend/utils/adt/Makefile.inc
Normal 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
618
src/backend/utils/adt/acl.c
Normal 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;
|
||||
}
|
||||
|
||||
|
||||
1375
src/backend/utils/adt/arrayfuncs.c
Normal file
1375
src/backend/utils/adt/arrayfuncs.c
Normal file
File diff suppressed because it is too large
Load Diff
111
src/backend/utils/adt/arrayutils.c
Normal file
111
src/backend/utils/adt/arrayutils.c
Normal 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);
|
||||
}
|
||||
|
||||
65
src/backend/utils/adt/bool.c
Normal file
65
src/backend/utils/adt/bool.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
392
src/backend/utils/adt/char.c
Normal file
392
src/backend/utils/adt/char.c
Normal 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));
|
||||
}
|
||||
587
src/backend/utils/adt/chunk.c
Normal file
587
src/backend/utils/adt/chunk.c
Normal 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;
|
||||
}
|
||||
|
||||
891
src/backend/utils/adt/date.c
Normal file
891
src/backend/utils/adt/date.c
Normal 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 */
|
||||
|
||||
}
|
||||
350
src/backend/utils/adt/datetimes.c
Normal file
350
src/backend/utils/adt/datetimes.c
Normal 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);
|
||||
}
|
||||
201
src/backend/utils/adt/datum.c
Normal file
201
src/backend/utils/adt/datum.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
58
src/backend/utils/adt/dt.c
Normal file
58
src/backend/utils/adt/dt.c
Normal 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) */
|
||||
120
src/backend/utils/adt/filename.c
Normal file
120
src/backend/utils/adt/filename.c
Normal 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));
|
||||
}
|
||||
1320
src/backend/utils/adt/float.c
Normal file
1320
src/backend/utils/adt/float.c
Normal file
File diff suppressed because it is too large
Load Diff
1947
src/backend/utils/adt/geo-ops.c
Normal file
1947
src/backend/utils/adt/geo-ops.c
Normal file
File diff suppressed because it is too large
Load Diff
124
src/backend/utils/adt/geo-selfuncs.c
Normal file
124
src/backend/utils/adt/geo-selfuncs.c
Normal 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
343
src/backend/utils/adt/int.c
Normal 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);
|
||||
}
|
||||
225
src/backend/utils/adt/like.c
Normal file
225
src/backend/utils/adt/like.c
Normal 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);
|
||||
}
|
||||
96
src/backend/utils/adt/misc.c
Normal file
96
src/backend/utils/adt/misc.c
Normal 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);
|
||||
}
|
||||
866
src/backend/utils/adt/nabstime.c
Normal file
866
src/backend/utils/adt/nabstime.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
198
src/backend/utils/adt/name.c
Normal file
198
src/backend/utils/adt/name.c
Normal 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;
|
||||
}
|
||||
124
src/backend/utils/adt/not_in.c
Normal file
124
src/backend/utils/adt/not_in.c
Normal 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);
|
||||
}
|
||||
|
||||
401
src/backend/utils/adt/numutils.c
Normal file
401
src/backend/utils/adt/numutils.c
Normal 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
127
src/backend/utils/adt/oid.c
Normal 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);
|
||||
}
|
||||
|
||||
120
src/backend/utils/adt/oidint2.c
Normal file
120
src/backend/utils/adt/oidint2.c
Normal 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);
|
||||
}
|
||||
|
||||
111
src/backend/utils/adt/oidint4.c
Normal file
111
src/backend/utils/adt/oidint4.c
Normal 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
123
src/backend/utils/adt/oidname.c
Normal file
123
src/backend/utils/adt/oidname.c
Normal 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;
|
||||
}
|
||||
343
src/backend/utils/adt/regexp.c
Normal file
343
src/backend/utils/adt/regexp.c
Normal 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));
|
||||
}
|
||||
|
||||
159
src/backend/utils/adt/regproc.c
Normal file
159
src/backend/utils/adt/regproc.c
Normal 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 ========== */
|
||||
|
||||
585
src/backend/utils/adt/selfuncs.c
Normal file
585
src/backend/utils/adt/selfuncs.c
Normal 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));
|
||||
}
|
||||
164
src/backend/utils/adt/sets.c
Normal file
164
src/backend/utils/adt/sets.c
Normal 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;
|
||||
}
|
||||
92
src/backend/utils/adt/tid.c
Normal file
92
src/backend/utils/adt/tid.c
Normal 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;
|
||||
}
|
||||
496
src/backend/utils/adt/varchar.c
Normal file
496
src/backend/utils/adt/varchar.c
Normal 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);
|
||||
}
|
||||
|
||||
488
src/backend/utils/adt/varlena.c
Normal file
488
src/backend/utils/adt/varlena.c
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user