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)