BIGINT 的 Postgres 最大值
Postgres maximum value for BIGINT
是否可以在不硬编码的情况下获得 BIGINT
类型的最大值?
我知道这个限制是众所周知的,但我不想对其进行硬编码。
您可以在 ~100 毫秒内达到它并在代码中使用或保存到临时文件 table - 这是或多或少快速获取最大值以提高它的示例:
do
$$
declare
i bigint =2;
r record;
begin
begin
for r in 2::int..999::int loop
i=power(2,r);
raise info '%', i::text;
end loop;
exception when others then raise info '%', 'fast roll on (power to 2) ended - switching to slow (multiplying by 2)'||i::text;
end;
begin
for r in 2::int..999::int loop
i=i*2;
raise info '%', i::text;
end loop;
exception when others then raise info '%', 'max reached:'||(1+(i-1)*2)::text;
end;
end;
$$
;
您可以使用 pg_column_size
,它会给您 bigint 的字节大小。使用它你可以得到它的最大和最小尺寸:
select (2^(8*pg_column_size(1::bigint)-2))::bigint << 1 as min_bigint_value;
select -(((2^(8*pg_column_size(1::bigint)-2))::bigint << 1)+1) as max_bigint_value;
因此,如果将来 bigint 最大值会以某种方式发生变化(非常非常不可能),如果您依赖这些计算值,您的代码仍然可以工作。
为了方便可以写函数:
CREATE OR REPLACE FUNCTION "get_max_bigint_value"() RETURNS BIGINT as $$
DECLARE
max_bigint_value BIGINT;
BEGIN
SELECT -(((2^(8*pg_column_size(1::BIGINT)-2))::BIGINT << 1)+1) INTO max_bigint_value;
RETURN max_bigint_value;
END
$$ LANGUAGE "plpgsql";
CREATE OR REPLACE FUNCTION "get_min_bigint_value"() RETURNS BIGINT as $$
DECLARE
min_bigint_value BIGINT;
BEGIN
SELECT (2^(8*pg_column_size(1::bigint)-2))::bigint << 1 INTO min_bigint_value;
RETURN min_bigint_value;
END
$$ LANGUAGE "plpgsql";
然后:
SELECT get_min_bigint_value();
SELECT get_max_bigint_value();
"ideal" 解决方案是创建一些仅公开相关定义的 C 函数(如下)。但假设你更愿意在 SQL 中拥有一些东西,我认为你能做的最好的事情是:
CREATE OR REPLACE FUNCTION bigint_min() RETURNS bigint LANGUAGE sql AS 'SELECT 1::bigint<<63';
CREATE OR REPLACE FUNCTION bigint_max() RETURNS bigint LANGUAGE sql AS 'SELECT ~bigint_min()';
CREATE OR REPLACE FUNCTION int_min() RETURNS int LANGUAGE sql AS 'SELECT 1<<31';
CREATE OR REPLACE FUNCTION int_max() RETURNS int LANGUAGE sql AS 'SELECT ~int_min()';
这些是在 C 级别定义的内容。 bigint 使用 PG_INT64_*:
#define PG_INT8_MIN (-0x7F-1)
#define PG_INT8_MAX (0x7F)
#define PG_UINT8_MAX (0xFF)
#define PG_INT16_MIN (-0x7FFF-1)
#define PG_INT16_MAX (0x7FFF)
#define PG_UINT16_MAX (0xFFFF)
#define PG_INT32_MIN (-0x7FFFFFFF-1)
#define PG_INT32_MAX (0x7FFFFFFF)
#define PG_UINT32_MAX (0xFFFFFFFFU)
#define PG_INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1)
#define PG_INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
#define PG_UINT64_MAX UINT64CONST(0xFFFFFFFFFFFFFFFF)
只是为了好玩:基于 alexpods 的回答,我们可以为所有 postgres 整数定义一个“通用”函数(假设是二进制补码):
create or replace function
minint(a anyelement)
returns anyelement
immutable
language sql
as $$
select ((a - a) - 1) << (8 * pg_column_size(a) - 1);
$$
;
create or replace
function maxint(a anyelement)
returns anyelement
immutable
language sql
as $$
select ~minint(a)
$$
;
用法:
select
minint(0::smallint)
, maxint(0::smallint)
, minint(0::int)
, maxint(0::int)
, minint(0::bigint)
, maxint(0::bigint)
;
结果:
minint | maxint | minint | maxint | minint | maxint
--------+--------+-------------+------------+----------------------+---------------------
-32768 | 32767 | -2147483648 | 2147483647 | -9223372036854775808 | 9223372036854775807
(1 row)
是否可以在不硬编码的情况下获得 BIGINT
类型的最大值?
我知道这个限制是众所周知的,但我不想对其进行硬编码。
您可以在 ~100 毫秒内达到它并在代码中使用或保存到临时文件 table - 这是或多或少快速获取最大值以提高它的示例:
do
$$
declare
i bigint =2;
r record;
begin
begin
for r in 2::int..999::int loop
i=power(2,r);
raise info '%', i::text;
end loop;
exception when others then raise info '%', 'fast roll on (power to 2) ended - switching to slow (multiplying by 2)'||i::text;
end;
begin
for r in 2::int..999::int loop
i=i*2;
raise info '%', i::text;
end loop;
exception when others then raise info '%', 'max reached:'||(1+(i-1)*2)::text;
end;
end;
$$
;
您可以使用 pg_column_size
,它会给您 bigint 的字节大小。使用它你可以得到它的最大和最小尺寸:
select (2^(8*pg_column_size(1::bigint)-2))::bigint << 1 as min_bigint_value;
select -(((2^(8*pg_column_size(1::bigint)-2))::bigint << 1)+1) as max_bigint_value;
因此,如果将来 bigint 最大值会以某种方式发生变化(非常非常不可能),如果您依赖这些计算值,您的代码仍然可以工作。
为了方便可以写函数:
CREATE OR REPLACE FUNCTION "get_max_bigint_value"() RETURNS BIGINT as $$
DECLARE
max_bigint_value BIGINT;
BEGIN
SELECT -(((2^(8*pg_column_size(1::BIGINT)-2))::BIGINT << 1)+1) INTO max_bigint_value;
RETURN max_bigint_value;
END
$$ LANGUAGE "plpgsql";
CREATE OR REPLACE FUNCTION "get_min_bigint_value"() RETURNS BIGINT as $$
DECLARE
min_bigint_value BIGINT;
BEGIN
SELECT (2^(8*pg_column_size(1::bigint)-2))::bigint << 1 INTO min_bigint_value;
RETURN min_bigint_value;
END
$$ LANGUAGE "plpgsql";
然后:
SELECT get_min_bigint_value();
SELECT get_max_bigint_value();
"ideal" 解决方案是创建一些仅公开相关定义的 C 函数(如下)。但假设你更愿意在 SQL 中拥有一些东西,我认为你能做的最好的事情是:
CREATE OR REPLACE FUNCTION bigint_min() RETURNS bigint LANGUAGE sql AS 'SELECT 1::bigint<<63';
CREATE OR REPLACE FUNCTION bigint_max() RETURNS bigint LANGUAGE sql AS 'SELECT ~bigint_min()';
CREATE OR REPLACE FUNCTION int_min() RETURNS int LANGUAGE sql AS 'SELECT 1<<31';
CREATE OR REPLACE FUNCTION int_max() RETURNS int LANGUAGE sql AS 'SELECT ~int_min()';
这些是在 C 级别定义的内容。 bigint 使用 PG_INT64_*:
#define PG_INT8_MIN (-0x7F-1)
#define PG_INT8_MAX (0x7F)
#define PG_UINT8_MAX (0xFF)
#define PG_INT16_MIN (-0x7FFF-1)
#define PG_INT16_MAX (0x7FFF)
#define PG_UINT16_MAX (0xFFFF)
#define PG_INT32_MIN (-0x7FFFFFFF-1)
#define PG_INT32_MAX (0x7FFFFFFF)
#define PG_UINT32_MAX (0xFFFFFFFFU)
#define PG_INT64_MIN (-INT64CONST(0x7FFFFFFFFFFFFFFF) - 1)
#define PG_INT64_MAX INT64CONST(0x7FFFFFFFFFFFFFFF)
#define PG_UINT64_MAX UINT64CONST(0xFFFFFFFFFFFFFFFF)
只是为了好玩:基于 alexpods 的回答,我们可以为所有 postgres 整数定义一个“通用”函数(假设是二进制补码):
create or replace function
minint(a anyelement)
returns anyelement
immutable
language sql
as $$
select ((a - a) - 1) << (8 * pg_column_size(a) - 1);
$$
;
create or replace
function maxint(a anyelement)
returns anyelement
immutable
language sql
as $$
select ~minint(a)
$$
;
用法:
select
minint(0::smallint)
, maxint(0::smallint)
, minint(0::int)
, maxint(0::int)
, minint(0::bigint)
, maxint(0::bigint)
;
结果:
minint | maxint | minint | maxint | minint | maxint
--------+--------+-------------+------------+----------------------+---------------------
-32768 | 32767 | -2147483648 | 2147483647 | -9223372036854775808 | 9223372036854775807
(1 row)