*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.107 2000/02/20 21:32:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.108 2000/02/21 18:47:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
newnode->type = from->type;
switch (from->type)
{
- case T_String:
- newnode->val.str = pstrdup(from->val.str);
- break;
case T_Integer:
newnode->val.ival = from->val.ival;
break;
case T_Float:
- newnode->val.dval = from->val.dval;
+ case T_String:
+ newnode->val.str = pstrdup(from->val.str);
break;
default:
break;
* VALUE NODES
*/
case T_Integer:
- case T_String:
case T_Float:
+ case T_String:
retval = _copyValue(from);
break;
case T_List:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.62 2000/02/20 21:32:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.63 2000/02/21 18:47:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
switch (a->type)
{
- case T_String:
- return strcmp(a->val.str, b->val.str);
case T_Integer:
return a->val.ival == b->val.ival;
case T_Float:
- return a->val.dval == b->val.dval;
+ case T_String:
+ return strcmp(a->val.str, b->val.str) == 0;
default:
break;
}
retval = _equalEState(a, b);
break;
case T_Integer:
- case T_String:
case T_Float:
+ case T_String:
retval = _equalValue(a, b);
break;
case T_List:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.37 2000/02/20 21:32:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.38 2000/02/21 18:47:00 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
switch (node->type)
{
- case T_String:
+ case T_Float:
+ case T_String:
pfree(node->val.str);
break;
default:
* VALUE NODES
*/
case T_Integer:
- case T_String:
case T_Float:
+ case T_String:
_freeValue(node);
break;
case T_List:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.29 2000/02/06 03:27:32 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.30 2000/02/21 18:47:00 tgl Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
/*
* makeFloat
+ *
+ * Caller is responsible for passing a palloc'd string.
*/
Value *
-makeFloat(double d)
+makeFloat(char *numericStr)
{
Value *v = makeNode(Value);
v->type = T_Float;
- v->val.dval = d;
+ v->val.str = numericStr;
return v;
}
/*
* makeString
+ *
+ * Caller is responsible for passing a palloc'd string.
*/
Value *
makeString(char *str)
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.109 2000/02/20 21:32:05 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.110 2000/02/21 18:47:00 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
{
switch (value->type)
{
- case T_String:
- appendStringInfo(str, " \"");
- _outToken(str, value->val.str);
- appendStringInfo(str, "\" ");
- break;
case T_Integer:
appendStringInfo(str, " %ld ", value->val.ival);
break;
case T_Float:
- appendStringInfo(str, " %.17g ", value->val.dval);
+ /* We assume the value is a valid numeric literal
+ * and so does not need quoting.
+ */
+ appendStringInfo(str, " %s ", value->val.str);
+ break;
+ case T_String:
+ appendStringInfo(str, " \"");
+ _outToken(str, value->val.str);
+ appendStringInfo(str, "\" ");
break;
default:
elog(NOTICE, "_outValue: don't know how to print type %d ",
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.20 2000/01/26 05:56:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/read.c,v 1.21 2000/02/21 18:47:00 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
*-------------------------------------------------------------------------
*/
#include <ctype.h>
+#include <errno.h>
#include "postgres.h"
nodeTokenType(char *token, int length)
{
NodeTag retval;
+ char *numptr;
+ int numlen;
+ char *endptr;
/*
- * Check if the token is a number (decimal or integer, positive or
- * negative)
+ * Check if the token is a number
*/
- if (isdigit(*token) ||
- (length >= 2 && *token == '-' && isdigit(token[1])))
+ numptr = token;
+ numlen = length;
+ if (*numptr == '+' || *numptr == '-')
+ numptr++, numlen--;
+ if ((numlen > 0 && isdigit(*numptr)) ||
+ (numlen > 1 && *numptr == '.' && isdigit(numptr[1])))
{
/*
- * skip the optional '-' (i.e. negative number)
+ * Yes. Figure out whether it is integral or float;
+ * this requires both a syntax check and a range check.
+ * strtol() can do both for us.
+ * We know the token will end at a character that strtol will
+ * stop at, so we do not need to modify the string.
*/
- if (*token == '-')
- token++, length--;
-
- /*
- * See if there is a decimal point
- */
- while (length > 0 && *token != '.')
- token++, length--;
-
- /*
- * if there isn't, token's an int, otherwise it's a float.
- */
- retval = (*token != '.') ? T_Integer : T_Float;
+ errno = 0;
+ (void) strtol(token, &endptr, 10);
+ if (endptr != token+length || errno == ERANGE)
+ return T_Float;
+ return T_Integer;
}
/*
* these three cases do not need length checks, since lsptok()
make_dotted_pair_cell = true;
}
break;
- case T_Float:
- /* we know that the token terminates on a char atof will stop at */
- this_value = (Node *) makeFloat(atof(token));
- make_dotted_pair_cell = true;
- break;
case T_Integer:
- /* we know that the token terminates on a char atoi will stop at */
- this_value = (Node *) makeInteger(atoi(token));
+ /* we know that the token terminates on a char atol will stop at */
+ this_value = (Node *) makeInteger(atol(token));
make_dotted_pair_cell = true;
break;
+ case T_Float:
+ {
+ char *fval = (char *) palloc(tok_len + 1);
+
+ memcpy(fval, token, tok_len);
+ fval[tok_len] = '\0';
+ this_value = (Node *) makeFloat(fval);
+ make_dotted_pair_cell = true;
+ }
+ break;
case T_String:
+ /* need to remove leading and trailing quotes, and backslashes */
this_value = (Node *) makeString(debackslash(token+1, tok_len-2));
make_dotted_pair_cell = true;
break;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.147 2000/02/20 02:14:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.148 2000/02/21 18:47:02 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
static void mapTargetColumns(List *source, List *target);
static void param_type_init(Oid *typev, int nargs);
static Node *doNegate(Node *n);
+static void doNegateFloat(Value *v);
/* old versions of flex define this as a macro */
#if defined(yywrap)
%union
{
- double dval;
int ival;
char chr;
char *str;
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
/* Special keywords, not in the query language - see the "lex" file */
-%token <str> IDENT, SCONST, Op
+%token <str> IDENT, FCONST, SCONST, Op
%token <ival> ICONST, PARAM
-%token <dval> FCONST
/* these are not real. they are here so that they get generated as #define's*/
%token OP
| '-' FCONST
{
$$ = makeFloat($2);
- $$->val.dval = - $$->val.dval;
+ doNegateFloat($$);
}
;
TriggerFuncArg: ICONST
{
- char *s = (char *) palloc (256);
+ char *s = (char *) palloc(64);
sprintf (s, "%d", $1);
$$ = s;
}
- | FCONST
- {
- char *s = (char *) palloc (256);
- sprintf (s, "%g", $1);
- $$ = s;
- }
+ | FCONST { $$ = $1; }
| Sconst { $$ = $1; }
| IDENT { $$ = $1; }
;
{
A_Const *n = makeNode(A_Const);
n->val.type = T_Float;
- n->val.val.dval = $1;
+ n->val.val.str = $1;
$$ = (Node *)n;
}
| Sconst
* a few cycles throughout the parse and rewrite stages if we collapse
* the minus into the constant sooner rather than later...
*/
-static Node *doNegate(Node *n)
+static Node *
+doNegate(Node *n)
{
if (IsA(n, A_Const))
{
}
if (con->val.type == T_Float)
{
- con->val.val.dval = -con->val.val.dval;
+ doNegateFloat(&con->val);
return n;
}
}
return makeA_Expr(OP, "-", NULL, n);
}
+
+static void
+doNegateFloat(Value *v)
+{
+ char *oldval = v->val.str;
+
+ Assert(IsA(v, Float));
+ if (*oldval == '+')
+ oldval++;
+ if (*oldval == '-')
+ v->val.str = oldval; /* just strip the '-' */
+ else
+ {
+ char *newval = (char *) palloc(strlen(oldval) + 2);
+
+ *newval = '-';
+ strcpy(newval+1, oldval);
+ v->val.str = newval;
+ }
+}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.69 2000/02/20 21:32:10 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.70 2000/02/21 18:47:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
switch (nodeTag(expr))
{
- case T_String:
- const_string = DatumGetPointer(expr->val.str);
- break;
case T_Integer:
string_palloced = true;
const_string = int4out(expr->val.ival);
break;
case T_Float:
- string_palloced = true;
- const_string = float8out(&expr->val.dval);
+ case T_String:
+ const_string = expr->val.str;
break;
case T_Null:
isNull = true;
break;
default:
- elog(ERROR,
- "Cannot cast this expression to type '%s'",
+ elog(ERROR, "Cannot cast this expression to type '%s'",
typename->name);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.64 2000/02/19 04:17:25 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/scan.l,v 1.65 2000/02/21 18:47:02 tgl Exp $
*
*-------------------------------------------------------------------------
*/
}
{param} {
- yylval.ival = atoi((char*)&yytext[1]);
+ yylval.ival = atol((char*)&yytext[1]);
return PARAM;
}
char* endptr;
errno = 0;
- yylval.ival = strtol((char *)yytext,&endptr,10);
+ yylval.ival = strtol((char *)yytext, &endptr, 10);
if (*endptr != '\0' || errno == ERANGE)
{
- errno = 0;
-#if 0
- yylval.dval = strtod(((char *)yytext),&endptr);
- if (*endptr != '\0' || errno == ERANGE)
- elog(ERROR,"Bad integer input '%s'",yytext);
- CheckFloat8Val(yylval.dval);
- elog(NOTICE,"Integer input '%s' is out of range; promoted to float", yytext);
- return FCONST;
-#endif
+ /* integer too large, treat it as a float */
yylval.str = pstrdup((char*)yytext);
- return SCONST;
+ return FCONST;
}
return ICONST;
}
{decimal} {
- char* endptr;
-
- if (strlen((char *)yytext) <= 17)
- {
- errno = 0;
- yylval.dval = strtod((char *)yytext,&endptr);
- if (*endptr != '\0' || errno == ERANGE)
- elog(ERROR,"Bad float input '%s'",yytext);
- CheckFloat8Val(yylval.dval);
- return FCONST;
- }
yylval.str = pstrdup((char*)yytext);
- return SCONST;
+ return FCONST;
}
{real} {
- char* endptr;
-
- errno = 0;
- yylval.dval = strtod((char *)yytext,&endptr);
- if (*endptr != '\0' || errno == ERANGE)
- elog(ERROR,"Bad float input '%s'",yytext);
- CheckFloat8Val(yylval.dval);
+ yylval.str = pstrdup((char*)yytext);
return FCONST;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.73 2000/02/17 05:00:38 inoue Exp $
+ * $Header: /cvsroot/pgsql/src/backend/storage/buffer/bufmgr.c,v 1.74 2000/02/21 18:47:03 tgl Exp $
*
*-------------------------------------------------------------------------
*/
*/
Assert(buf->refcount == 0);
buf->refcount = 1;
+ Assert(PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] == 0);
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 1;
if (buf->flags & BM_DIRTY)
inProgress = FALSE;
buf->flags &= ~BM_IO_IN_PROGRESS;
TerminateBufferIO(buf);
+ Assert(PrivateRefCount[BufferDescriptorGetBuffer(buf)-1] == 1);
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
buf->refcount--;
buf = (BufferDesc *) NULL;
{
TerminateBufferIO(buf);
/* give up the buffer since we don't need it any more */
+ Assert(PrivateRefCount[BufferDescriptorGetBuffer(buf)-1] == 1);
PrivateRefCount[BufferDescriptorGetBuffer(buf) - 1] = 0;
Assert(buf->refcount > 0);
buf->refcount--;
if (!(buf->flags & BM_FREE))
{
/* Assert checks that buffer will actually get freed! */
- Assert(PrivateRefCount[i - 1] == 1 &&
- buf->refcount == 1);
+ Assert(buf->refcount == 1);
+ if (PrivateRefCount[i - 1] <= 0)
+ {
+ fprintf(stderr, "Nonpositive PrivateRefCount on buffer for %s\n",
+ RelationGetRelationName(rel));
+ fflush(stderr);
+ * ((char *) 0) = 0;
+ abort();
+ }
+ Assert(PrivateRefCount[i - 1] == 1);
/* ReleaseBuffer expects we do not hold the lock at entry */
SpinRelease(BufMgrLock);
holding = false;
* is for IP V4 CIDR notation, but prepared for V6: just
* add the necessary bits where the comments indicate.
*
- * $Id: network.c,v 1.16 1999/09/23 17:42:23 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/network.c,v 1.17 2000/02/21 18:47:07 tgl Exp $
+ *
* Jon Postel RIP 16 Oct 1998
*/
+#include "postgres.h"
+
#include <sys/types.h>
#include <sys/socket.h>
-
#include <errno.h>
-
#include <netinet/in.h>
#include <arpa/inet.h>
-#include "postgres.h"
#include "utils/builtins.h"
-static int v4bitncmp(unsigned int a1, unsigned int a2, int bits);
+
+static int v4bitncmp(unsigned long a1, unsigned long a2, int bits);
/*
* Access macros. Add IPV6 support.
#define ip_v4addr(inetptr) \
(((inet_struct *)VARDATA(inetptr))->addr.ipv4_addr)
+
/* Common input routine */
static inet *
network_in(char *src, int type)
}
/*
- * Boolean tests for magnitude. Add V4/V6 testing!
+ * Boolean tests for ordering operators --- must agree with sorting
+ * operator network_cmp().
*/
bool
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
- if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
- {
- int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
-
- return ((order < 0) || ((order == 0) && (ip_bits(a1) < ip_bits(a2))));
- }
- else
- {
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "cannot compare address families %d and %d",
- ip_family(a1), ip_family(a2));
- return FALSE;
- }
+ return (bool) (network_cmp(a1, a2) < 0);
}
bool
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
- return (network_lt(a1, a2) || network_eq(a1, a2));
+ return (bool) (network_cmp(a1, a2) <= 0);
}
bool
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
- if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
- {
- return ((ip_bits(a1) == ip_bits(a2))
- && (v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a1)) == 0));
- }
- else
- {
- /* Go for an IPV6 address here, before faulting out: */
- elog(ERROR, "cannot compare address families %d and %d",
- ip_family(a1), ip_family(a2));
- return FALSE;
- }
+ return (bool) (network_cmp(a1, a2) == 0);
}
bool
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
- return (network_gt(a1, a2) || network_eq(a1, a2));
+ return (bool) (network_cmp(a1, a2) >= 0);
}
bool
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
return FALSE;
+ return (bool) (network_cmp(a1, a2) > 0);
+}
+
+bool
+network_ne(inet *a1, inet *a2)
+{
+ if (!PointerIsValid(a1) || !PointerIsValid(a2))
+ return FALSE;
+ return (bool) (network_cmp(a1, a2) != 0);
+}
+
+/*
+ * Comparison function for sorting. Add V4/V6 testing!
+ */
+
+int4
+network_cmp(inet *a1, inet *a2)
+{
if ((ip_family(a1) == AF_INET) && (ip_family(a2) == AF_INET))
{
- int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2), ip_bits(a2));
-
- return ((order > 0) || ((order == 0) && (ip_bits(a1) > ip_bits(a2))));
+ int order = v4bitncmp(ip_v4addr(a1), ip_v4addr(a2),
+ (ip_bits(a1) < ip_bits(a2)) ?
+ ip_bits(a1) : ip_bits(a2));
+
+ if (order)
+ return order;
+ /* They agree in the first N bits, so shorter one comes first */
+ return (int) ip_bits(a1) - (int) ip_bits(a2);
}
else
{
/* Go for an IPV6 address here, before faulting out: */
elog(ERROR, "cannot compare address families %d and %d",
ip_family(a1), ip_family(a2));
- return FALSE;
+ return 0;
}
}
bool
-network_ne(inet *a1, inet *a2)
-{
- if (!PointerIsValid(a1) || !PointerIsValid(a2))
- return FALSE;
- return (!network_eq(a1, a2));
-}
-
-bool
network_sub(inet *a1, inet *a2)
{
if (!PointerIsValid(a1) || !PointerIsValid(a2))
}
}
-/*
- * Comparison function for sorting. Add V4/V6 testing!
- */
-
-int4
-network_cmp(inet *a1, inet *a2)
-{
- if (ntohl(ip_v4addr(a1)) < ntohl(ip_v4addr(a2)))
- return (-1);
-
- if (ntohl(ip_v4addr(a1)) > ntohl(ip_v4addr(a2)))
- return (1);
-
- if (ip_bits(a1) < ip_bits(a2))
- return (-1);
-
- if (ip_bits(a1) > ip_bits(a2))
- return (1);
-
- return 0;
-}
-
text *
network_host(inet *ip)
{
*/
static int
-v4bitncmp(unsigned int a1, unsigned int a2, int bits)
+v4bitncmp(unsigned long a1, unsigned long a2, int bits)
{
unsigned long mask = 0;
int i;
mask = (mask >> 1) | 0x80000000;
a1 = ntohl(a1);
a2 = ntohl(a2);
- if ((a1 & mask) < (a2 & mask))
+ a1 &= mask;
+ a2 &= mask;
+ if (a1 < a2)
return (-1);
- else if ((a1 & mask) > (a2 & mask))
+ else if (a1 > a2)
return (1);
return (0);
}
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_list.h,v 1.15 2000/02/06 03:27:35 tgl Exp $
+ * $Id: pg_list.h,v 1.16 2000/02/21 18:47:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*----------------------
* Value node
+ *
+ * The same Value struct is used for three node types: T_Integer,
+ * T_Float, and T_String. Integral values are actually represented
+ * by a machine integer, but both floats and strings are represented
+ * as strings. Using T_Float as the node type simply indicates that
+ * the contents of the string look like a valid numeric literal.
+ *
+ * (Before Postgres 7.0, we used a double to represent T_Float,
+ * but that creates loss-of-precision problems when the value is
+ * ultimately destined to be converted to NUMERIC. Since Value nodes
+ * are only used in the parsing process, not for runtime data, it's
+ * better to use the more general representation.)
+ *
+ * Note that an integer-looking string will get lexed as T_Float if
+ * the value is too large to fit in a 'long'.
*----------------------
*/
typedef struct Value
NodeTag type; /* tag appropriately (eg. T_String) */
union ValUnion
{
+ long ival; /* machine integer */
char *str; /* string */
- long ival;
- double dval;
} val;
} Value;
#define intVal(v) (((Value *)(v))->val.ival)
-#define floatVal(v) (((Value *)(v))->val.dval)
+#define floatVal(v) atof(((Value *)(v))->val.str)
#define strVal(v) (((Value *)(v))->val.str)
extern bool member(void *datum, List *list);
extern bool intMember(int datum, List *list);
extern Value *makeInteger(long i);
-extern Value *makeFloat(double d);
+extern Value *makeFloat(char *numericStr);
extern Value *makeString(char *str);
-extern List *makeList(void *elem,...);
+extern List *makeList(void *elem, ...);
extern List *lappend(List *list, void *datum);
extern List *lappendi(List *list, int datum);
extern List *lremove(void *elem, List *list);