GOOGLE ADS

jueves, 14 de abril de 2022

¿Existe una forma adecuada de manejar los cursores devueltos por una función postgresql en psycopg?

Estoy tratando de hacerme amigo de postgresql (14.0 compilación 1914 de 64 bits en Windows), psycopg2 (2.9.1 instalado usando pip) y Python 3.8.10 en Windows.

Creé una función postgresql en una base de datos que devuelve un cursor, algo así como a continuación

CREATE get_rows 
...
RETURNS refcursor
...
DECLARE
res1 refcursor;
BEGIN
OPEN res1 FOR
SELECT some_field, and_another_field FROM some_table;
RETURN res1;
END

La función se puede ejecutar desde la herramienta pgAdmin4 Quert
SELECT get_rows(); y luego devolverá un cursor como "<portal 1 sin nombre>"

Todavía dentro de la herramienta de consulta en pgAdmin4 puedo emitir:

BEGIN;
SELECT get_rows();
FETCH ALL IN "<unnamed portal 2>"; -- Adjust counter number

Y esto me dará las filas devueltas por el cursor.

Ahora quiero replicar esto usando psycopg en lugar de pgAdmin4

tengo el siguiente codigo

conn = psycopg2.connect("dbname='" + db_name + "' "\
"user='" + db_user + "' " +\
"host='" + db_host + "' "+\
"password='" + db_passwd + "'")
cursor = conn.cursor()
cursor.callproc('get_rows')
print("cursor.description: ", end = '')
print(cursor.description)
for record in cursor:
print("record: ", end = '')
print (record)

El código anterior solo proporciona el nombre de la cadena del cursor (como lo devuelve la función postgresql 'get_rows') en el único registro del cursor creado por psycopg.

¿Cómo puedo obtener un objeto de clase de cursor de psycopg que proporcione acceso al cursor devuelto por 'get_rows'?

https://www.psycopg.org/docs/cursor.html dice cursor.name es de solo lectura y no veo una forma obvia de conectar el cursor de 'get_rows' con una instancia de cursor psycopg


Solución del problema

El enlace del cursor que muestra se refiere al cursor de la API de la base de datos de Python, no al de Postgres. Hay un ejemplo de cómo hacer lo que quiere aquí Cursor del lado del servidor en la sección:

Nota También es posible usar un cursor con nombre para consumir un cursor creado de otra manera que no sea usando DECLARE ejecutado por execute(). Por ejemplo, puede tener una función PL/pgSQL que devuelva un cursor:

CREATE FUNCTION reffunc(refcursor) RETURNS refcursor AS $$
BEGIN
OPEN $1 FOR SELECT col FROM test;
RETURN $1;
END;
$$ LANGUAGE plpgsql;

Puede leer el contenido del cursor llamando a la función con un cursor Psycopg regular, sin nombre:

cur1 = conn.cursor()
cur1.callproc('reffunc', ['curname'])
and then use a named cursor in the same transaction to "steal the cursor":
cur2 = conn.cursor('curname')
for record in cur2: # or cur2.fetchone, fetchmany...
# do something with record
pass

ACTUALIZAR

Asegúrese de cerrar named cursor(cur2) para liberar el cursor del lado del servidor. Asi que:

cur2.close()

No hay comentarios.:

Publicar un comentario

Flutter: error de rango al acceder a la respuesta JSON

Estoy accediendo a una respuesta JSON con la siguiente estructura. { "fullName": "FirstName LastName", "listings...