42.5. Acesso a banco de dados pelo PL/Tcl #

Nesta seção, é seguida a convenção usual do Tcl de usar pontos de interrogação, em vez de colchetes, para indicar um elemento opcional em uma sinopse de sintaxe. Os seguintes comandos estão disponíveis para acessar o banco de dados a partir do corpo de uma função PL/Tcl:

spi_exec ?-count n? ?-array nome? comando ?corpo-do-laço?

Executa o comando SQL fornecido como uma cadeia de caracteres. Um erro no comando faz com que seja relatado um erro. Caso contrário, o valor retornado pela função spi_exec será o número de linhas processadas (selecionadas, inseridas, atualizadas, ou excluídas) pelo comando, ou zero se o comando for uma instrução utilitária. Além disso, se o comando for uma instrução SELECT, os valores das colunas selecionadas serão colocados em variáveis Tcl conforme descrito abaixo.

O valor opcional -count indica ao spi_exec para parar quando n linhas forem recuperadas, como se a consulta incluísse uma cláusula LIMIT. Se n for zero, a consulta será executada até o final, da mesma forma que quando -count é omitido.

Se o comando for uma instrução SELECT, os valores das colunas do resultado serão colocados em variáveis Tcl com nomes derivados das colunas. Se for fornecida a opção -array, os valores das colunas serão armazenados nos elementos da matriz associativa indicada, com os nomes das colunas usados como índices da matriz. Além disso, o número da linha corrente no resultado (contando a partir de zero) é armazenado no elemento da matriz denominado .tupno, a menos que este nome esteja em uso como nome de coluna no resultado.

Se o comando for uma instrução SELECT, e não for fornecido nenhum script para corpo-do-laço, então apenas a primeira linha do resultado será armazenada em variáveis Tcl ou elementos da matriz; as linhas restantes, se houver, serão ignoradas. Nenhum armazenamento irá ocorrer se a consulta não retornar nenhuma linha. (Este caso pode ser detectado verificando o resultado da função spi_exec.) Por exemplo:

spi_exec "SELECT count(*) AS cnt FROM pg_proc"

irá definir a variável $cnt do Tcl para o número de linhas no catálogo do sistema pg_proc.

Se for fornecido o argumento opcional corpo-do-laço, ele será um trecho de script Tcl que será executado uma vez para cada linha no resultado da consulta. (O corpo-do-laço será ignorado se o comando fornecido não for um SELECT.) Os valores das colunas da linha corrente são armazenados em variáveis ou elementos da matriz do Tcl, antes de cada iteração. Por exemplo:

spi_exec -array C "SELECT * FROM pg_class" {
    elog DEBUG "tem a tabela $C(relname)"
}

irá imprimir uma mensagem de registro para cada linha do catálogo pg_class. Este recurso funciona de forma semelhante a outras construções de laço Tcl; em particular, continue e break funcionam da maneira usual dentro do corpo do laço.

Se uma coluna do resultado de uma consulta for nula, a variável de destino dela será unset, em vez de ser definida.

spi_prepare query lista_de_tipos_de_dados

Prepara e salva um plano de consulta para execução posterior. O plano salvo será mantido durante a sessão corrente.

A consulta pode utilizar parâmetros, ou seja, espaços reservados para valores a serem fornecidos sempre que o plano for realmente executado. Na cadeia de caracteres da consulta, os parâmetros são acessados pelos símbolos $1 ... $n. Se a consulta utilizar parâmetros, os nomes dos tipos de dados dos parâmetros deverão ser fornecidos como uma lista Tcl. (Deve-se escrever uma lista vazia para a lista-de-tipos se não for usado nenhum parâmetro.)

O valor retornado por spi_prepare é o identificador da consulta a ser usado nas chamadas subsequentes da função spi_execp. Veja exemplo em spi_execp.

spi_execp ?-count n? ?-array nome? ?-nulls cadeia-de-caracteres? id-consulta ?lista-de-valores? ?corpo-do-laço?

Executa a consulta previamente preparada pela função spi_prepare. id-consulta é o identificador retornado pela função spi_prepare. Se a consulta fizer referência a parâmetros, deverá ser fornecida uma lista-de-valores. Esta é uma lista Tcl contendo os valores reais para os parâmetros. A lista deve ter o mesmo comprimento que a lista de tipos de dados de parâmetro fornecida anteriormente para a função spi_prepare. A lista-de-valores deverá ser omitida se a consulta não tiver parâmetros.

O valor opcional para -nulls é uma cadeia de caracteres de espaços e caracteres 'n' informando à função spi_execp quais dos parâmetros são valores nulos. Se for fornecida, deverá ter exatamente o mesmo comprimento que a lista-de-valores. Se não for fornecida, todos os valores dos parâmetros serão não-nulos.

Exceto pela forma como a consulta e seus parâmetros são especificados, a função spi_execp funciona exatamente como a função spi_exec. As opções -count, -array, e corpo-do-laço, são iguais, assim como o valor do resultado.

A seguir está um exemplo de uma função PL/Tcl usando um plano preparado:

CREATE FUNCTION t1_count(integer, integer) RETURNS integer AS $$
    if {![ info exists GD(plan) ]} {
        # preparar o plano salvo na primeira chamada
        set GD(plan) [ spi_prepare \
                "SELECT count(*) AS cnt FROM t1 WHERE num >= \$1 AND num <= \$2" \
                [ list int4 int4 ] ]
    }
    spi_execp -count 1 $GD(plan) [ list $1 $2 ]
    return $cnt
$$ LANGUAGE pltcl;

São necessárias contrabarras dentro da cadeia de caracteres da consulta fornecida à função spi_prepare, para garantir que os marcadores $n serão passados para a função spi_prepare como estão, e não substituídos pela substituição de variável do Tcl.

subtransaction comando

O script Tcl contido no comando é executado em uma subtransação SQL. Se o script retornar um erro, toda a subtransação será desfeita antes de retornar o erro para o código Tcl envoltório. Veja Subtransações explícitas em PL/Tcl para obter mais detalhes e um exemplo.

quote cadeia-de-caracteres

Duplica todas as ocorrências de caracteres de apóstrofos e contrabarras na cadeia de caracteres fornecida. Pode ser usado para delimitar com segurança cadeias de caracteres que serão inseridas em comandos SQL fornecidos à função spi_exec ou à função spi_prepare. Por exemplo, imagine uma cadeia de caracteres de comando SQL como:

"SELECT '$val' AS ret"

onde a variável Tcl val contém doesn't. Isto resultaria na cadeia de caracteres de comando final:

SELECT 'doesn't' AS ret

o que causaria um erro de análise nas funções spi_exec e spi_prepare. Para funcionar corretamente, o comando enviado deve conter:

SELECT 'doesn''t' AS ret

que pode ser formado no PL/Tcl usando:

"SELECT '[ quote $val ]' AS ret"

Uma vantagem da função spi_execp é não ser necessário delimitar valores de parâmetros como este, já que os parâmetros nunca são analisados como parte da cadeia de caracteres do comando SQL.

elog level msg

Produz um registro ou mensagem de erro. Os níveis possíveis são DEBUG, LOG, INFO, NOTICE, WARNING, ERROR, e FATAL. ERROR gera uma condição de erro; se não for capturada pelo código Tcl envoltório, o erro irá se propagar para a consulta de chamada, fazendo com que a transação ou a subtransação corrente seja interrompida. Isto é efetivamente o mesmo que o comando error do Tcl. FATAL interrompe a transação e faz com que a sessão corrente seja encerrada. (Provavelmente não há uma boa razão para usar este nível de erro em funções PL/Tcl, mas é fornecido para ficar completo.) Os demais níveis geram apenas mensagens de diferentes níveis de prioridade. Se as mensagens de uma determinada prioridade são relatadas ao cliente, escritas no registro de eventos do servidor, ou as duas coisas, é controlado pelas variáveis de configuração log_min_messages e client_min_messages. Veja Configuração do servidor e Tratamento de erro em PL/Tcl para obter mais informações.