|
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
|
*
|
|
|
|
|
* int8.c
|
|
|
|
|
* Internal 64-bit integer operations
|
|
|
|
|
*
|
|
|
|
|
* Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
|
|
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
|
*
|
|
|
|
|
* IDENTIFICATION
|
|
|
|
|
* src/backend/utils/adt/int8.c
|
|
|
|
|
*
|
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
|
*/
|
|
|
|
|
#include "postgres.h"
|
|
|
|
|
|
|
|
|
|
#include <ctype.h>
|
|
|
|
|
#include <limits.h>
|
|
|
|
|
#include <math.h>
|
|
|
|
|
|
|
|
|
|
#include "common/int.h"
|
|
|
|
|
#include "funcapi.h"
|
|
|
|
|
#include "libpq/pqformat.h"
|
|
|
|
|
#include "nodes/nodeFuncs.h"
|
|
|
|
|
#include "nodes/supportnodes.h"
|
|
|
|
|
#include "optimizer/optimizer.h"
|
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
|
#include "utils/fmgroids.h"
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
int64 current;
|
|
|
|
|
int64 finish;
|
|
|
|
|
int64 step;
|
|
|
|
|
} generate_series_fctx;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
|
**
|
|
|
|
|
** Routines for 64-bit integers.
|
|
|
|
|
**
|
|
|
|
|
***********************************************************************/
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
* Formatting and conversion routines.
|
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
/* int8in()
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8in(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
char *num = PG_GETARG_CSTRING(0);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
Convert a few datatype input functions to use "soft" error reporting.
This patch converts the input functions for bool, int2, int4, int8,
float4, float8, numeric, and contrib/cube to the new soft-error style.
array_in and record_in are also converted. There's lots more to do,
but this is enough to provide proof-of-concept that the soft-error
API is usable, as well as reference examples for how to convert
input functions.
This patch is mostly by me, but it owes very substantial debt to
earlier work by Nikita Glukhov, Andrew Dunstan, and Amul Sul.
Thanks to Andres Freund for review.
Discussion: https://postgr.es/m/3bbbb0df-7382-bf87-9737-340ba096e034@postgrespro.ru
3 years ago
|
|
|
PG_RETURN_INT64(pg_strtoint64_safe(num, fcinfo->context));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* int8out()
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8out(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val = PG_GETARG_INT64(0);
|
|
|
|
|
char buf[MAXINT8LEN + 1];
|
|
|
|
|
char *result;
|
|
|
|
|
int len;
|
|
|
|
|
|
|
|
|
|
len = pg_lltoa(val, buf) + 1;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Since the length is already known, we do a manual palloc() and memcpy()
|
|
|
|
|
* to avoid the strlen() call that would otherwise be done in pstrdup().
|
|
|
|
|
*/
|
|
|
|
|
result = palloc(len);
|
|
|
|
|
memcpy(result, buf, len);
|
|
|
|
|
PG_RETURN_CSTRING(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* int8recv - converts external binary format to int8
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8recv(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(pq_getmsgint64(buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* int8send - converts int8 to binary format
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8send(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
StringInfoData buf;
|
|
|
|
|
|
|
|
|
|
pq_begintypsend(&buf);
|
|
|
|
|
pq_sendint64(&buf, arg1);
|
|
|
|
|
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
* Relational operators for int8s, including cross-data-type comparisons.
|
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
/* int8relop()
|
|
|
|
|
* Is val1 relop val2?
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 == val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 != val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 < val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 > val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 <= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 >= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int84relop()
|
|
|
|
|
* Is 64-bit val1 relop 32-bit val2?
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int84eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 == val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 != val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 < val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 > val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 <= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 val2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 >= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int48relop()
|
|
|
|
|
* Is 32-bit val1 relop 64-bit val2?
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int48eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 == val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 != val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 < val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 > val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 <= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 val1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 >= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int82relop()
|
|
|
|
|
* Is 64-bit val1 relop 16-bit val2?
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int82eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 == val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 != val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 < val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 > val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 <= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 val2 = PG_GETARG_INT16(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 >= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int28relop()
|
|
|
|
|
* Is 16-bit val1 relop 64-bit val2?
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int28eq(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 == val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28ne(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 != val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28lt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 < val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28gt(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 > val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28le(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 <= val2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28ge(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 val1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 val2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_BOOL(val1 >= val2);
|
|
|
|
|
}
|
|
|
|
|
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
8 years ago
|
|
|
/*
|
|
|
|
|
* in_range support function for int8.
|
|
|
|
|
*
|
|
|
|
|
* Note: we needn't supply int8_int4 or int8_int2 variants, as implicit
|
|
|
|
|
* coercion of the offset value takes care of those scenarios just as well.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
in_range_int8_int8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 val = PG_GETARG_INT64(0);
|
|
|
|
|
int64 base = PG_GETARG_INT64(1);
|
|
|
|
|
int64 offset = PG_GETARG_INT64(2);
|
|
|
|
|
bool sub = PG_GETARG_BOOL(3);
|
|
|
|
|
bool less = PG_GETARG_BOOL(4);
|
|
|
|
|
int64 sum;
|
|
|
|
|
|
|
|
|
|
if (offset < 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
|
Support all SQL:2011 options for window frame clauses.
This patch adds the ability to use "RANGE offset PRECEDING/FOLLOWING"
frame boundaries in window functions. We'd punted on that back in the
original patch to add window functions, because it was not clear how to
do it in a reasonably data-type-extensible fashion. That problem is
resolved here by adding the ability for btree operator classes to provide
an "in_range" support function that defines how to add or subtract the
RANGE offset value. Factoring it this way also allows the operator class
to avoid overflow problems near the ends of the datatype's range, if it
wishes to expend effort on that. (In the committed patch, the integer
opclasses handle that issue, but it did not seem worth the trouble to
avoid overflow failures for datetime types.)
The patch includes in_range support for the integer_ops opfamily
(int2/int4/int8) as well as the standard datetime types. Support for
other numeric types has been requested, but that seems like suitable
material for a follow-on patch.
In addition, the patch adds GROUPS mode which counts the offset in
ORDER-BY peer groups rather than rows, and it adds the frame_exclusion
options specified by SQL:2011. As far as I can see, we are now fully
up to spec on window framing options.
Existing behaviors remain unchanged, except that I changed the errcode
for a couple of existing error reports to meet the SQL spec's expectation
that negative "offset" values should be reported as SQLSTATE 22013.
Internally and in relevant parts of the documentation, we now consistently
use the terminology "offset PRECEDING/FOLLOWING" rather than "value
PRECEDING/FOLLOWING", since the term "value" is confusingly vague.
Oliver Ford, reviewed and whacked around some by me
Discussion: https://postgr.es/m/CAGMVOdu9sivPAxbNN0X+q19Sfv9edEPv=HibOJhB14TJv_RCQg@mail.gmail.com
8 years ago
|
|
|
errmsg("invalid preceding or following size in window function")));
|
|
|
|
|
|
|
|
|
|
if (sub)
|
|
|
|
|
offset = -offset; /* cannot overflow */
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow(base, offset, &sum)))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* If sub is false, the true sum is surely more than val, so correct
|
|
|
|
|
* answer is the same as "less". If sub is true, the true sum is
|
|
|
|
|
* surely less than val, so the answer is "!less".
|
|
|
|
|
*/
|
|
|
|
|
PG_RETURN_BOOL(sub ? !less : less);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (less)
|
|
|
|
|
PG_RETURN_BOOL(val <= sum);
|
|
|
|
|
else
|
|
|
|
|
PG_RETURN_BOOL(val >= sum);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
* Arithmetic operators on 64-bit integers.
|
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8um(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
result = -arg;
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8up(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8pl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow(arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8mi(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow(arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8mul(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8div(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (arg2 == 0)
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* INT64_MIN / -1 is problematic, since the result can't be represented on
|
|
|
|
|
* a two's-complement machine. Some machines produce INT64_MIN, some
|
|
|
|
|
* produce zero, some throw an exception. We can dodge the problem by
|
|
|
|
|
* recognizing that division by -1 is the same as negation.
|
|
|
|
|
*/
|
|
|
|
|
if (arg2 == -1)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(arg1 == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
result = -arg1;
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
|
|
|
|
|
result = arg1 / arg2;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int8abs()
|
|
|
|
|
* Absolute value
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8abs(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg1 == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
result = (arg1 < 0) ? -arg1 : arg1;
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* int8mod()
|
|
|
|
|
* Modulo operation.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8mod(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg2 == 0))
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Some machines throw a floating-point exception for INT64_MIN % -1,
|
|
|
|
|
* which is a bit silly since the correct answer is perfectly
|
|
|
|
|
* well-defined, namely zero.
|
|
|
|
|
*/
|
|
|
|
|
if (arg2 == -1)
|
|
|
|
|
PG_RETURN_INT64(0);
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 % arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Greatest Common Divisor
|
|
|
|
|
*
|
|
|
|
|
* Returns the largest positive integer that exactly divides both inputs.
|
|
|
|
|
* Special cases:
|
|
|
|
|
* - gcd(x, 0) = gcd(0, x) = abs(x)
|
|
|
|
|
* because 0 is divisible by anything
|
|
|
|
|
* - gcd(0, 0) = 0
|
|
|
|
|
* complies with the previous definition and is a common convention
|
|
|
|
|
*
|
|
|
|
|
* Special care must be taken if either input is INT64_MIN ---
|
|
|
|
|
* gcd(0, INT64_MIN), gcd(INT64_MIN, 0) and gcd(INT64_MIN, INT64_MIN) are
|
|
|
|
|
* all equal to abs(INT64_MIN), which cannot be represented as a 64-bit signed
|
|
|
|
|
* integer.
|
|
|
|
|
*/
|
|
|
|
|
static int64
|
|
|
|
|
int8gcd_internal(int64 arg1, int64 arg2)
|
|
|
|
|
{
|
|
|
|
|
int64 swap;
|
|
|
|
|
int64 a1,
|
|
|
|
|
a2;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Put the greater absolute value in arg1.
|
|
|
|
|
*
|
|
|
|
|
* This would happen automatically in the loop below, but avoids an
|
|
|
|
|
* expensive modulo operation, and simplifies the special-case handling
|
|
|
|
|
* for INT64_MIN below.
|
|
|
|
|
*
|
|
|
|
|
* We do this in negative space in order to handle INT64_MIN.
|
|
|
|
|
*/
|
|
|
|
|
a1 = (arg1 < 0) ? arg1 : -arg1;
|
|
|
|
|
a2 = (arg2 < 0) ? arg2 : -arg2;
|
|
|
|
|
if (a1 > a2)
|
|
|
|
|
{
|
|
|
|
|
swap = arg1;
|
|
|
|
|
arg1 = arg2;
|
|
|
|
|
arg2 = swap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Special care needs to be taken with INT64_MIN. See comments above. */
|
|
|
|
|
if (arg1 == PG_INT64_MIN)
|
|
|
|
|
{
|
|
|
|
|
if (arg2 == 0 || arg2 == PG_INT64_MIN)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Some machines throw a floating-point exception for INT64_MIN % -1,
|
|
|
|
|
* which is a bit silly since the correct answer is perfectly
|
|
|
|
|
* well-defined, namely zero. Guard against this and just return the
|
|
|
|
|
* result, gcd(INT64_MIN, -1) = 1.
|
|
|
|
|
*/
|
|
|
|
|
if (arg2 == -1)
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Use the Euclidean algorithm to find the GCD */
|
|
|
|
|
while (arg2 != 0)
|
|
|
|
|
{
|
|
|
|
|
swap = arg2;
|
|
|
|
|
arg2 = arg1 % arg2;
|
|
|
|
|
arg1 = swap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Make sure the result is positive. (We know we don't have INT64_MIN
|
|
|
|
|
* anymore).
|
|
|
|
|
*/
|
|
|
|
|
if (arg1 < 0)
|
|
|
|
|
arg1 = -arg1;
|
|
|
|
|
|
|
|
|
|
return arg1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8gcd(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
result = int8gcd_internal(arg1, arg2);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Least Common Multiple
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8lcm(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 gcd;
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Handle lcm(x, 0) = lcm(0, x) = 0 as a special case. This prevents a
|
|
|
|
|
* division-by-zero error below when x is zero, and an overflow error from
|
|
|
|
|
* the GCD computation when x = INT64_MIN.
|
|
|
|
|
*/
|
|
|
|
|
if (arg1 == 0 || arg2 == 0)
|
|
|
|
|
PG_RETURN_INT64(0);
|
|
|
|
|
|
|
|
|
|
/* lcm(x, y) = abs(x / gcd(x, y) * y) */
|
|
|
|
|
gcd = int8gcd_internal(arg1, arg2);
|
|
|
|
|
arg1 = arg1 / gcd;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow(arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
/* If the result is INT64_MIN, it cannot be represented. */
|
|
|
|
|
if (unlikely(result == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
if (result < 0)
|
|
|
|
|
result = -result;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8inc(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow(arg, 1, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8dec(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow(arg, 1, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* These functions are exactly like int8inc/int8dec but are used for
|
|
|
|
|
* aggregates that count only non-null values. Since the functions are
|
|
|
|
|
* declared strict, the null checks happen before we ever get here, and all we
|
|
|
|
|
* need do is increment the state value. We could actually make these pg_proc
|
|
|
|
|
* entries point right at int8inc/int8dec, but then the opr_sanity regression
|
|
|
|
|
* test would complain about mismatched entries for a built-in function.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8inc_any(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return int8inc(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8inc_float8_float8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return int8inc(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8dec_any(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return int8dec(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
Teach planner and executor about monotonic window funcs
Window functions such as row_number() always return a value higher than
the previously returned value for tuples in any given window partition.
Traditionally queries such as;
SELECT * FROM (
SELECT *, row_number() over (order by c) rn
FROM t
) t WHERE rn <= 10;
were executed fairly inefficiently. Neither the query planner nor the
executor knew that once rn made it to 11 that nothing further would match
the outer query's WHERE clause. It would blindly continue until all
tuples were exhausted from the subquery.
Here we implement means to make the above execute more efficiently.
This is done by way of adding a pg_proc.prosupport function to various of
the built-in window functions and adding supporting code to allow the
support function to inform the planner if the window function is
monotonically increasing, monotonically decreasing, both or neither. The
planner is then able to make use of that information and possibly allow
the executor to short-circuit execution by way of adding a "run condition"
to the WindowAgg to allow it to determine if some of its execution work
can be skipped.
This "run condition" is not like a normal filter. These run conditions
are only built using quals comparing values to monotonic window functions.
For monotonic increasing functions, quals making use of the btree
operators for <, <= and = can be used (assuming the window function column
is on the left). You can see here that once such a condition becomes false
that a monotonic increasing function could never make it subsequently true
again. For monotonically decreasing functions the >, >= and = btree
operators for the given type can be used for run conditions.
The best-case situation for this is when there is a single WindowAgg node
without a PARTITION BY clause. Here when the run condition becomes false
the WindowAgg node can simply return NULL. No more tuples will ever match
the run condition. It's a little more complex when there is a PARTITION
BY clause. In this case, we cannot return NULL as we must still process
other partitions. To speed this case up we pull tuples from the outer
plan to check if they're from the same partition and simply discard them
if they are. When we find a tuple belonging to another partition we start
processing as normal again until the run condition becomes false or we run
out of tuples to process.
When there are multiple WindowAgg nodes to evaluate then this complicates
the situation. For intermediate WindowAggs we must ensure we always
return all tuples to the calling node. Any filtering done could lead to
incorrect results in WindowAgg nodes above. For all intermediate nodes,
we can still save some work when the run condition becomes false. We've
no need to evaluate the WindowFuncs anymore. Other WindowAgg nodes cannot
reference the value of these and these tuples will not appear in the final
result anyway. The savings here are small in comparison to what can be
saved in the top-level WingowAgg, but still worthwhile.
Intermediate WindowAgg nodes never filter out tuples, but here we change
WindowAgg so that the top-level WindowAgg filters out tuples that don't
match the intermediate WindowAgg node's run condition. Such filters
appear in the "Filter" clause in EXPLAIN for the top-level WindowAgg node.
Here we add prosupport functions to allow the above to work for;
row_number(), rank(), dense_rank(), count(*) and count(expr). It appears
technically possible to do the same for min() and max(), however, it seems
unlikely to be useful enough, so that's not done here.
Bump catversion
Author: David Rowley
Reviewed-by: Andy Fan, Zhihong Yu
Discussion: https://postgr.es/m/CAApHDvqvp3At8++yF8ij06sdcoo1S_b2YoaT9D4Nf+MObzsrLQ@mail.gmail.com
4 years ago
|
|
|
/*
|
|
|
|
|
* int8inc_support
|
|
|
|
|
* prosupport function for int8inc() and int8inc_any()
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
int8inc_support(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
|
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestWFuncMonotonic))
|
|
|
|
|
{
|
|
|
|
|
SupportRequestWFuncMonotonic *req = (SupportRequestWFuncMonotonic *) rawreq;
|
|
|
|
|
MonotonicFunction monotonic = MONOTONICFUNC_NONE;
|
|
|
|
|
int frameOptions = req->window_clause->frameOptions;
|
|
|
|
|
|
|
|
|
|
/* No ORDER BY clause then all rows are peers */
|
|
|
|
|
if (req->window_clause->orderClause == NIL)
|
|
|
|
|
monotonic = MONOTONICFUNC_BOTH;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Otherwise take into account the frame options. When the frame
|
|
|
|
|
* bound is the start of the window then the resulting value can
|
|
|
|
|
* never decrease, therefore is monotonically increasing
|
|
|
|
|
*/
|
|
|
|
|
if (frameOptions & FRAMEOPTION_START_UNBOUNDED_PRECEDING)
|
|
|
|
|
monotonic |= MONOTONICFUNC_INCREASING;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Likewise, if the frame bound is the end of the window then the
|
|
|
|
|
* resulting value can never decrease.
|
|
|
|
|
*/
|
|
|
|
|
if (frameOptions & FRAMEOPTION_END_UNBOUNDED_FOLLOWING)
|
|
|
|
|
monotonic |= MONOTONICFUNC_DECREASING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req->monotonic = monotonic;
|
|
|
|
|
PG_RETURN_POINTER(req);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestSimplifyAggref))
|
|
|
|
|
{
|
|
|
|
|
SupportRequestSimplifyAggref *req = (SupportRequestSimplifyAggref *) rawreq;
|
|
|
|
|
Aggref *agg = req->aggref;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Check for COUNT(ANY) and try to convert to COUNT(*). The input
|
|
|
|
|
* argument cannot be NULL, we can't have an ORDER BY / DISTINCT in
|
|
|
|
|
* the aggregate, and agglevelsup must be 0.
|
|
|
|
|
*
|
|
|
|
|
* Technically COUNT(ANY) must have 1 arg, but be paranoid and check.
|
|
|
|
|
*/
|
|
|
|
|
if (agg->aggfnoid == F_COUNT_ANY && list_length(agg->args) == 1)
|
|
|
|
|
{
|
|
|
|
|
TargetEntry *tle = (TargetEntry *) linitial(agg->args);
|
|
|
|
|
Expr *arg = tle->expr;
|
|
|
|
|
|
|
|
|
|
/* Check for unsupported cases */
|
|
|
|
|
if (agg->aggdistinct != NIL || agg->aggorder != NIL ||
|
|
|
|
|
agg->agglevelsup != 0)
|
|
|
|
|
PG_RETURN_POINTER(NULL);
|
|
|
|
|
|
|
|
|
|
/* If the arg isn't NULLable, do the conversion */
|
|
|
|
|
if (expr_is_nonnullable(req->root, arg, false))
|
|
|
|
|
{
|
|
|
|
|
Aggref *newagg;
|
|
|
|
|
|
|
|
|
|
/* We don't expect these to have been set yet */
|
|
|
|
|
Assert(agg->aggtransno == -1);
|
|
|
|
|
Assert(agg->aggtranstype == InvalidOid);
|
|
|
|
|
|
|
|
|
|
/* Convert COUNT(ANY) to COUNT(*) by making a new Aggref */
|
|
|
|
|
newagg = makeNode(Aggref);
|
|
|
|
|
memcpy(newagg, agg, sizeof(Aggref));
|
|
|
|
|
newagg->aggfnoid = F_COUNT_;
|
|
|
|
|
|
|
|
|
|
/* count(*) has no args */
|
|
|
|
|
newagg->aggargtypes = NULL;
|
|
|
|
|
newagg->args = NULL;
|
|
|
|
|
newagg->aggstar = true;
|
|
|
|
|
newagg->location = -1;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(newagg);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Teach planner and executor about monotonic window funcs
Window functions such as row_number() always return a value higher than
the previously returned value for tuples in any given window partition.
Traditionally queries such as;
SELECT * FROM (
SELECT *, row_number() over (order by c) rn
FROM t
) t WHERE rn <= 10;
were executed fairly inefficiently. Neither the query planner nor the
executor knew that once rn made it to 11 that nothing further would match
the outer query's WHERE clause. It would blindly continue until all
tuples were exhausted from the subquery.
Here we implement means to make the above execute more efficiently.
This is done by way of adding a pg_proc.prosupport function to various of
the built-in window functions and adding supporting code to allow the
support function to inform the planner if the window function is
monotonically increasing, monotonically decreasing, both or neither. The
planner is then able to make use of that information and possibly allow
the executor to short-circuit execution by way of adding a "run condition"
to the WindowAgg to allow it to determine if some of its execution work
can be skipped.
This "run condition" is not like a normal filter. These run conditions
are only built using quals comparing values to monotonic window functions.
For monotonic increasing functions, quals making use of the btree
operators for <, <= and = can be used (assuming the window function column
is on the left). You can see here that once such a condition becomes false
that a monotonic increasing function could never make it subsequently true
again. For monotonically decreasing functions the >, >= and = btree
operators for the given type can be used for run conditions.
The best-case situation for this is when there is a single WindowAgg node
without a PARTITION BY clause. Here when the run condition becomes false
the WindowAgg node can simply return NULL. No more tuples will ever match
the run condition. It's a little more complex when there is a PARTITION
BY clause. In this case, we cannot return NULL as we must still process
other partitions. To speed this case up we pull tuples from the outer
plan to check if they're from the same partition and simply discard them
if they are. When we find a tuple belonging to another partition we start
processing as normal again until the run condition becomes false or we run
out of tuples to process.
When there are multiple WindowAgg nodes to evaluate then this complicates
the situation. For intermediate WindowAggs we must ensure we always
return all tuples to the calling node. Any filtering done could lead to
incorrect results in WindowAgg nodes above. For all intermediate nodes,
we can still save some work when the run condition becomes false. We've
no need to evaluate the WindowFuncs anymore. Other WindowAgg nodes cannot
reference the value of these and these tuples will not appear in the final
result anyway. The savings here are small in comparison to what can be
saved in the top-level WingowAgg, but still worthwhile.
Intermediate WindowAgg nodes never filter out tuples, but here we change
WindowAgg so that the top-level WindowAgg filters out tuples that don't
match the intermediate WindowAgg node's run condition. Such filters
appear in the "Filter" clause in EXPLAIN for the top-level WindowAgg node.
Here we add prosupport functions to allow the above to work for;
row_number(), rank(), dense_rank(), count(*) and count(expr). It appears
technically possible to do the same for min() and max(), however, it seems
unlikely to be useful enough, so that's not done here.
Bump catversion
Author: David Rowley
Reviewed-by: Andy Fan, Zhihong Yu
Discussion: https://postgr.es/m/CAApHDvqvp3At8++yF8ij06sdcoo1S_b2YoaT9D4Nf+MObzsrLQ@mail.gmail.com
4 years ago
|
|
|
PG_RETURN_POINTER(NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8larger(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
result = ((arg1 > arg2) ? arg1 : arg2);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8smaller(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
result = ((arg1 < arg2) ? arg1 : arg2);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84pl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84mi(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84mul(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84div(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (arg2 == 0)
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* INT64_MIN / -1 is problematic, since the result can't be represented on
|
|
|
|
|
* a two's-complement machine. Some machines produce INT64_MIN, some
|
|
|
|
|
* produce zero, some throw an exception. We can dodge the problem by
|
|
|
|
|
* recognizing that division by -1 is the same as negation.
|
|
|
|
|
*/
|
|
|
|
|
if (arg2 == -1)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(arg1 == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
result = -arg1;
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
|
|
|
|
|
result = arg1 / arg2;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48pl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 arg1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48mi(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 arg1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48mul(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 arg1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48div(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 arg1 = PG_GETARG_INT32(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg2 == 0))
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
PG_RETURN_INT64((int64) arg1 / arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82pl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 arg2 = PG_GETARG_INT16(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82mi(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 arg2 = PG_GETARG_INT16(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82mul(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 arg2 = PG_GETARG_INT16(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow(arg1, (int64) arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82div(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int16 arg2 = PG_GETARG_INT16(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg2 == 0))
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* INT64_MIN / -1 is problematic, since the result can't be represented on
|
|
|
|
|
* a two's-complement machine. Some machines produce INT64_MIN, some
|
|
|
|
|
* produce zero, some throw an exception. We can dodge the problem by
|
|
|
|
|
* recognizing that division by -1 is the same as negation.
|
|
|
|
|
*/
|
|
|
|
|
if (arg2 == -1)
|
|
|
|
|
{
|
|
|
|
|
if (unlikely(arg1 == PG_INT64_MIN))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
result = -arg1;
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
|
|
|
|
|
result = arg1 / arg2;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28pl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 arg1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_add_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28mi(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 arg1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_sub_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28mul(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 arg1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
int64 result;
|
|
|
|
|
|
|
|
|
|
if (unlikely(pg_mul_s64_overflow((int64) arg1, arg2, &result)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
PG_RETURN_INT64(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28div(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 arg1 = PG_GETARG_INT16(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg2 == 0))
|
|
|
|
|
{
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DIVISION_BY_ZERO),
|
|
|
|
|
errmsg("division by zero")));
|
|
|
|
|
/* ensure compiler realizes we mustn't reach the division (gcc bug) */
|
|
|
|
|
PG_RETURN_NULL();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No overflow is possible */
|
|
|
|
|
PG_RETURN_INT64((int64) arg1 / arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Binary arithmetics
|
|
|
|
|
*
|
|
|
|
|
* int8and - returns arg1 & arg2
|
|
|
|
|
* int8or - returns arg1 | arg2
|
|
|
|
|
* int8xor - returns arg1 # arg2
|
|
|
|
|
* int8not - returns ~arg1
|
|
|
|
|
* int8shl - returns arg1 << arg2
|
|
|
|
|
* int8shr - returns arg1 >> arg2
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8and(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 & arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8or(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 | arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8xor(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int64 arg2 = PG_GETARG_INT64(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 ^ arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8not(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(~arg1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8shl(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 << arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int8shr(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg1 = PG_GETARG_INT64(0);
|
|
|
|
|
int32 arg2 = PG_GETARG_INT32(1);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64(arg1 >> arg2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
|
|
|
* Conversion operators.
|
|
|
|
|
*---------------------------------------------------------*/
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int48(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int32 arg = PG_GETARG_INT32(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64((int64) arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int84(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg < PG_INT32_MIN) || unlikely(arg > PG_INT32_MAX))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("integer out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT32((int32) arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int28(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int16 arg = PG_GETARG_INT16(0);
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64((int64) arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
int82(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
|
|
|
|
|
if (unlikely(arg < PG_INT16_MIN) || unlikely(arg > PG_INT16_MAX))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("smallint out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT16((int16) arg);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
i8tod(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
|
|
|
|
float8 result;
|
|
|
|
|
|
|
|
|
|
result = arg;
|
|
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT8(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* dtoi8()
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
* Convert float8 to 8-byte integer.
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
dtoi8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
float8 num = PG_GETARG_FLOAT8(0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
|
*/
|
|
|
|
|
num = rint(num);
|
|
|
|
|
|
|
|
|
|
/* Range check */
|
|
|
|
|
if (unlikely(isnan(num) || !FLOAT8_FITS_IN_INT64(num)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
|
|
|
|
|
|
|
|
|
PG_RETURN_INT64((int64) num);
|
|
|
|
|
}
|
|
|
|
|
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
Datum
|
|
|
|
|
i8tof(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
float4 result;
|
|
|
|
|
|
|
|
|
|
result = arg;
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
PG_RETURN_FLOAT4(result);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ftoi8()
|
|
|
|
|
* Convert float4 to 8-byte integer.
|
|
|
|
|
*/
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
Datum
|
|
|
|
|
ftoi8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
float4 num = PG_GETARG_FLOAT4(0);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Get rid of any fractional part in the input. This is so we don't fail
|
|
|
|
|
* on just-out-of-range values that would round into range. Note
|
|
|
|
|
* assumption that rint() will pass through a NaN or Inf unchanged.
|
|
|
|
|
*/
|
|
|
|
|
num = rint(num);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
/* Range check */
|
|
|
|
|
if (unlikely(isnan(num) || !FLOAT4_FITS_IN_INT64(num)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("bigint out of range")));
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
PG_RETURN_INT64((int64) num);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
i8tooid(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
int64 arg = PG_GETARG_INT64(0);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
if (unlikely(arg < 0) || unlikely(arg > PG_UINT32_MAX))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
|
|
|
|
|
errmsg("OID out of range")));
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
PG_RETURN_OID((Oid) arg);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
oidtoi8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Oid arg = PG_GETARG_OID(0);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
|
|
|
|
|
PG_RETURN_INT64((int64) arg);
|
Extend pg_cast castimplicit column to a three-way value; this allows us
to be flexible about assignment casts without introducing ambiguity in
operator/function resolution. Introduce a well-defined promotion hierarchy
for numeric datatypes (int2->int4->int8->numeric->float4->float8).
Change make_const to initially label numeric literals as int4, int8, or
numeric (never float8 anymore).
Explicitly mark Func and RelabelType nodes to indicate whether they came
from a function call, explicit cast, or implicit cast; use this to do
reverse-listing more accurately and without so many heuristics.
Explicit casts to char, varchar, bit, varbit will truncate or pad without
raising an error (the pre-7.2 behavior), while assigning to a column without
any explicit cast will still raise an error for wrong-length data like 7.3.
This more nearly follows the SQL spec than 7.2 behavior (we should be
reporting a 'completion condition' in the explicit-cast cases, but we have
no mechanism for that, so just do silent truncation).
Fix some problems with enforcement of typmod for array elements;
it didn't work at all in 'UPDATE ... SET array[n] = foo', for example.
Provide a generalized array_length_coerce() function to replace the
specialized per-array-type functions that used to be needed (and were
missing for NUMERIC as well as all the datetime types).
Add missing conversions int8<->float4, text<->numeric, oid<->int8.
initdb forced.
24 years ago
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* non-persistent numeric series generator
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
generate_series_int8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
return generate_series_step_int8(fcinfo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Datum
|
|
|
|
|
generate_series_step_int8(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
FuncCallContext *funcctx;
|
|
|
|
|
generate_series_fctx *fctx;
|
|
|
|
|
int64 result;
|
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
|
|
/* stuff done only on the first call of the function */
|
|
|
|
|
if (SRF_IS_FIRSTCALL())
|
|
|
|
|
{
|
|
|
|
|
int64 start = PG_GETARG_INT64(0);
|
|
|
|
|
int64 finish = PG_GETARG_INT64(1);
|
|
|
|
|
int64 step = 1;
|
|
|
|
|
|
|
|
|
|
/* see if we were given an explicit step size */
|
|
|
|
|
if (PG_NARGS() == 3)
|
|
|
|
|
step = PG_GETARG_INT64(2);
|
|
|
|
|
if (step == 0)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Wording cleanup for error messages. Also change can't -> cannot.
Standard English uses "may", "can", and "might" in different ways:
may - permission, "You may borrow my rake."
can - ability, "I can lift that log."
might - possibility, "It might rain today."
Unfortunately, in conversational English, their use is often mixed, as
in, "You may use this variable to do X", when in fact, "can" is a better
choice. Similarly, "It may crash" is better stated, "It might crash".
19 years ago
|
|
|
errmsg("step size cannot equal zero")));
|
|
|
|
|
|
|
|
|
|
/* create a function context for cross-call persistence */
|
|
|
|
|
funcctx = SRF_FIRSTCALL_INIT();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* switch to memory context appropriate for multiple function calls
|
|
|
|
|
*/
|
|
|
|
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
|
|
|
|
|
|
|
|
|
/* allocate memory for user context */
|
|
|
|
|
fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Use fctx to keep state from call to call. Seed current with the
|
|
|
|
|
* original start value
|
|
|
|
|
*/
|
|
|
|
|
fctx->current = start;
|
|
|
|
|
fctx->finish = finish;
|
|
|
|
|
fctx->step = step;
|
|
|
|
|
|
|
|
|
|
funcctx->user_fctx = fctx;
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* stuff done on every call of the function */
|
|
|
|
|
funcctx = SRF_PERCALL_SETUP();
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* get the saved state and use current as the result for this iteration
|
|
|
|
|
*/
|
|
|
|
|
fctx = funcctx->user_fctx;
|
|
|
|
|
result = fctx->current;
|
|
|
|
|
|
|
|
|
|
if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
|
|
|
|
|
(fctx->step < 0 && fctx->current >= fctx->finish))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Increment current in preparation for next iteration. If next-value
|
|
|
|
|
* computation overflows, this is the final result.
|
|
|
|
|
*/
|
|
|
|
|
if (pg_add_s64_overflow(fctx->current, fctx->step, &fctx->current))
|
|
|
|
|
fctx->step = 0;
|
|
|
|
|
|
|
|
|
|
/* do when there is more left to send */
|
|
|
|
|
SRF_RETURN_NEXT(funcctx, Int64GetDatum(result));
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/* do when there is no more left */
|
|
|
|
|
SRF_RETURN_DONE(funcctx);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Planner support function for generate_series(int8, int8 [, int8])
|
|
|
|
|
*/
|
|
|
|
|
Datum
|
|
|
|
|
generate_series_int8_support(PG_FUNCTION_ARGS)
|
|
|
|
|
{
|
|
|
|
|
Node *rawreq = (Node *) PG_GETARG_POINTER(0);
|
|
|
|
|
Node *ret = NULL;
|
|
|
|
|
|
|
|
|
|
if (IsA(rawreq, SupportRequestRows))
|
|
|
|
|
{
|
|
|
|
|
/* Try to estimate the number of rows returned */
|
|
|
|
|
SupportRequestRows *req = (SupportRequestRows *) rawreq;
|
|
|
|
|
|
|
|
|
|
if (is_funcclause(req->node)) /* be paranoid */
|
|
|
|
|
{
|
|
|
|
|
List *args = ((FuncExpr *) req->node)->args;
|
|
|
|
|
Node *arg1,
|
|
|
|
|
*arg2,
|
|
|
|
|
*arg3;
|
|
|
|
|
|
|
|
|
|
/* We can use estimated argument values here */
|
|
|
|
|
arg1 = estimate_expression_value(req->root, linitial(args));
|
|
|
|
|
arg2 = estimate_expression_value(req->root, lsecond(args));
|
|
|
|
|
if (list_length(args) >= 3)
|
|
|
|
|
arg3 = estimate_expression_value(req->root, lthird(args));
|
|
|
|
|
else
|
|
|
|
|
arg3 = NULL;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If any argument is constant NULL, we can safely assume that
|
|
|
|
|
* zero rows are returned. Otherwise, if they're all non-NULL
|
|
|
|
|
* constants, we can calculate the number of rows that will be
|
|
|
|
|
* returned. Use double arithmetic to avoid overflow hazards.
|
|
|
|
|
*/
|
|
|
|
|
if ((IsA(arg1, Const) &&
|
|
|
|
|
((Const *) arg1)->constisnull) ||
|
|
|
|
|
(IsA(arg2, Const) &&
|
|
|
|
|
((Const *) arg2)->constisnull) ||
|
|
|
|
|
(arg3 != NULL && IsA(arg3, Const) &&
|
|
|
|
|
((Const *) arg3)->constisnull))
|
|
|
|
|
{
|
|
|
|
|
req->rows = 0;
|
|
|
|
|
ret = (Node *) req;
|
|
|
|
|
}
|
|
|
|
|
else if (IsA(arg1, Const) &&
|
|
|
|
|
IsA(arg2, Const) &&
|
|
|
|
|
(arg3 == NULL || IsA(arg3, Const)))
|
|
|
|
|
{
|
|
|
|
|
double start,
|
|
|
|
|
finish,
|
|
|
|
|
step;
|
|
|
|
|
|
|
|
|
|
start = DatumGetInt64(((Const *) arg1)->constvalue);
|
|
|
|
|
finish = DatumGetInt64(((Const *) arg2)->constvalue);
|
|
|
|
|
step = arg3 ? DatumGetInt64(((Const *) arg3)->constvalue) : 1;
|
|
|
|
|
|
|
|
|
|
/* This equation works for either sign of step */
|
|
|
|
|
if (step != 0)
|
|
|
|
|
{
|
|
|
|
|
req->rows = floor((finish - start + step) / step);
|
|
|
|
|
ret = (Node *) req;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PG_RETURN_POINTER(ret);
|
|
|
|
|
}
|