Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

272
Visualizações
How to give a default value of ksuid in postgres to a column? Is there any alternative of ksuid in postgres?

I have a char field whose default value should be a ksuid. How to generate a ksuid in postgres?

over 4 years ago · Santiago Trujillo
3 Respostas
Responde à pergunta

0

I suggest your best option is to create a user DOMAIN. Then define a function to generate your ksuid. Then alter the domain to to use this function as the default. When needed define your column as that DOMAIN type.

-- setup domain and the generating function
create domain ksuid character varying(27);
    
create or replace function generate_ksuid()
 returns  ksuid
 language sql 
as $$
    select substring(
             replace(to_char(clock_timestamp(),'yyyymmddhh24missus') 
                     || (to_char(random()*1e9,'000000000')
                    ),' ',''),1,27)::ksuid;
$$; 
 
alter domain ksuid set default generate_ksuid();

See complete example, including using, here. Of course the function generate_ksuid will need to be adapted to your requirement. The example is just based on clock_timestamp and a random number.

over 4 years ago · Santiago Trujillo Relatório

0

This function generates KSUID on PostgreSQL. It uses numeric data type to convert time and payload to base62.

It creates a pseudo-random payload using the native MD5() function. If you want to use pgcrypto, check out the @ssz's comment. Thank you @ssz!

The KSUIDs generated by the function are compliant with the reference implementation.

/**
 * Returns a Segment's KSUID.
 *
 * Reference implementation: https://github.com/segmentio/ksuid
 * Also read: https://segment.com/blog/a-brief-history-of-the-uuid/
 */
create or replace function fn_ksuid() returns text as $$
declare
    v_time timestamp with time zone := null;
    v_seconds numeric := null;
    v_payload bytea := null;
    v_numeric numeric := null;
    v_base62 text := '';
    v_epoch numeric = 1400000000; -- 2014-05-13T16:53:20Z
    v_alphabet char array[62] := array[
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
        'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 
        'U', 'V', 'W', 'X', 'Y', 'Z', 
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 
        'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
        'u', 'v', 'w', 'x', 'y', 'z'];
    i integer := 0;
begin

    -- Get the current time
    v_time := clock_timestamp();

    -- Extract seconds from the current time and apply epoch
    v_seconds := EXTRACT(EPOCH FROM v_time) - v_epoch;

    -- Generate a numeric value from the seconds
    v_numeric := v_seconds * pow(2::numeric, 128);

    -- Generate a pseudo-random payload
    -- v_payload := gen_random_bytes(16); -- to be used with `pgcrypto`
    v_payload := decode(md5(v_time::text || random()::text || random()::text), 'hex');
    
    -- Add the payload to the numeric value
    while i < 16 loop
        i := i + 1;
        v_numeric := v_numeric + (get_byte(v_payload, i - 1) * pow(2::numeric, (16 - i) * 8));
    end loop;
    
    -- Encode the numeric value to base62
    while v_numeric <> 0 loop
        v_base62 := v_base62 || v_alphabet[mod(v_numeric, 62) + 1];
        v_numeric := div(v_numeric, 62);
    end loop;
    v_base62 := reverse(v_base62);
    v_base62 := lpad(v_base62, 27, '0');

    return v_base62;
    
end $$ language plpgsql;

Link to GitHub Gist.

over 4 years ago · Santiago Trujillo Relatório

0

I'd like to suggest a slight change to the fabiolimace`s solution. Instead:

v_payload := decode(md5(v_time::text || random()::text || random()::text), 'hex');

use more strong function gen_random_bytes():

v_payload := gen_random_bytes(16);

It requires pgcrypto extension to be enabled:

CREATE EXTENSION pgcrypto;

Important update

In some rare cases this function returns NULL. An error occurs on line:

v_base62 := v_base62 || v_alphabet[mod(v_numeric, 62) + 1];

Example:

mod(v_numeric, 62) 'Let`s say this function returns 61.7977600000000000000000'
mod(v_numeric, 62) + 1 '62.7977600000000000000000'
v_alphabet[62.7977600000000000000000 => 63] => NULL '62.7977600000000000000000 rounds to 63, there is no element with index 63'
v_base62 || NULL 'v_base62 becomes NULL because || operator always returns NULL if at least one of the operands is null'

How to reproduce:

SELECT COUNT(*)
FROM (SELECT fn_ksuid() AS id FROM GENERATE_SERIES(1, 1000)) q
WHERE q.id IS NULL;

Solution:

v_base62 := v_base62 || v_alphabet[floor(mod(v_numeric, 62)) + 1];

Always cast the mod value to the integer part using floor() function.

In real life the error occurs when a large number of rows are inserted at the same time.

over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda