Re: SPI_connect

From: Yessica Brinkmann <yessica(dot)brinkmann(at)gmail(dot)com>
To: Enrique Herrera Noya <enrique(dot)herreranoya(at)gmail(dot)com>
Cc: Francisco Olarte <folarte(at)peoplecall(dot)com>, Postgres Español <pgsql-es-ayuda(at)postgresql(dot)org>
Subject: Re: SPI_connect
Date: 2019-09-17 19:19:48
Message-ID: CABrYqSPiF+EQ2hmoDAn1JOuPOiA4sGbtTywsHBY=3mi=E1SM6g@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-es-ayuda

Buenas tardes,
Estuve haciendo algunas verificaciones y lastimosamente pude darme cuenta
de que luego de ejecutar el Index Adviser básicamente no me aparece nada en
el directorio /var/log/postgresql, es decir dicho directorio aparece vacío,
sin ningún archivo. Realmente veo que dicho directorio existe, sin embargo
luego de levantar el servidor Postgresql y ejecutar el Index Adviser me
aparece vacío, no hay allí ningún archivo de log. No sé a qué se deberá
esto realmente. Como les comentaba, no soy buena usando Linux, pero me veo
obligada a usarlo.
Por otro lado, hice un diagrama de la estructura del Index Adviser, que es
simplemente un gráfico explicativo de lo que dice el readme del Index
Adviser. Adjunto a este mail como documento .pdf, para que no sea
muy pesado, ya que según me habían dicho las imágenes son muy pesadas para
anexarlas a los mails.
Finalmente, copio el código fuente de la función que contiene el Insert que
funciona con el SPI_connect(), y a continuación, las dos funciones que yo
estoy intentando escribir, que tienen Selects, y con las cuales obtengo
el SPI_ERROR_CONNECT.
Saludos cordiales,
Yessica
/**
* save_advice
* for every candidate insert an entry into IND_ADV_TABL
*/
static void
save_advice( List* candidates )
{
StringInfoData query; /* string for Query */
StringInfoData cols; /* string for Columns */
Oid advise_oid;
ListCell *cell;

elog( DEBUG3, "IND ADV: save_advice: ENTER" );

Assert( list_length(candidates) != 0 );

/*
* Minimal check: check that IND_ADV_TABL is at least visible to us. There
* are a lot more checks we should do in order to not let the INSERT fail,
* like permissions, datatype mis-match, etc., but we leave those checks
* upto the executor.
*/

/* find a relation named IND_ADV_TABL on the search path */
advise_oid = RelnameGetRelid( IND_ADV_TABL );

if (advise_oid != InvalidOid)
{
#if 1
Relation advise_rel = relation_open(advise_oid, AccessShareLock);

if (advise_rel->rd_rel->relkind != RELKIND_RELATION
&& advise_rel->rd_rel->relkind != RELKIND_VIEW)
{
relation_close(advise_rel, AccessShareLock);

/* FIXME: add errdetail() and/or errcontext() calls here. */
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg( IND_ADV_ERROR_NTV )));
}

relation_close(advise_rel, AccessShareLock);
#else
/*
* heap_open() makes sure that the oid does not represent an INDEX or a
* COMPOSITE type, else it will raise an ERROR, which is exactly what we
* want. The comments above heap_open() ask the caller not to assume any
* storage since the returned relation may be a VIEW; but we don't mind,
* since the user may have defined some rules on it to make the INSERTs
* work smoothly! If not, we leave it upto the executor to raise ERROR.
*/
PG_TRY();
{
heap_close(heap_open(advise_oid, AccessShareLock), AccessShareLock);
}
PG_CATCH();
{
errmsg( IND_ADV_ERROR_NTV );
PG_RE_THROW();
}
PG_END_TRY();
#endif
}
else
{
/* FIXME: add errdetail() and/or errcontext() calls here. */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg( IND_ADV_ERROR_NE )));
}

initStringInfo( &query );
initStringInfo( &cols );

foreach( cell, candidates )
{
int i;
IndexCandidate* idxcd = (IndexCandidate*)lfirst( cell );

if( !idxcd->idxused )
continue;

/* pfree() the memory allocated for the previous candidate. FIXME: Avoid
* meddling with the internals of a StringInfo, and try to use an API.
*/
if( cols.len > 0 )
{
pfree( cols.data );
cols.data = NULL;
}

initStringInfo( &cols );

for (i = 0; i < idxcd->ncols; ++i)
appendStringInfo( &cols, "%s%d", (i>0?",":""), idxcd->varattno[i]);

/* FIXME: Mention the column names explicitly after the table name. */
appendStringInfo( &query, "insert into \""IND_ADV_TABL"\" values"
"( %d, array[%s], %f, %d, %d, now());",
idxcd->reloid,
cols.data,
idxcd->benefit,
idxcd->pages * BLCKSZ/1024, /* in KBs */
MyProcPid );
} /* foreach cell in candidates */

if( query.len > 0 ) /* if we generated any SQL */
{
if( SPI_connect() == SPI_OK_CONNECT )
{
if( SPI_execute( query.data, false, 0 ) != SPI_OK_INSERT )
elog( WARNING, "IND ADV: SPI_execute failed while saving advice." );

if( SPI_finish() != SPI_OK_FINISH )
elog( WARNING, "IND ADV: SPI_finish failed while saving advice." );
}
else
elog( WARNING, "IND ADV: SPI_connect failed while saving advice." );
}

/* TODO: Propose to -hackers to introduce API to free a StringInfoData . */
if ( query.len > 0 )
pfree( query.data );

if ( cols.len > 0 )
pfree( cols.data );

elog( DEBUG3, "IND ADV: save_advice: EXIT" );
}

/**
* get_distinct
* for every candidate get an entry into IndexCandidate
*/
static void
get_ndistinct( List* candidates )
{
int proc;
StringInfoData query; /* string for Query */
StringInfoData cols; /* string for Columns */
Oid advise_oid;
ListCell *cell;

SPITupleTable *SPI_tuptable;

TupleDesc tupdesc;

elog( DEBUG3, "IND ADV: get_distinct: ENTER" );

Assert( list_length(candidates) != 0 );

/*
* Minimal check: check that IND_ADV_TABL is at least visible to us. There
* are a lot more checks we should do in order to not let the INSERT fail,
* like permissions, datatype mis-match, etc., but we leave those checks
* upto the executor.
*/

/* find a relation named IND_ADV_TABL on the search path */
advise_oid = RelnameGetRelid( IND_ADV_TABL );

if (advise_oid != InvalidOid)
{
#if 1
Relation advise_rel = relation_open(advise_oid, AccessShareLock);

if (advise_rel->rd_rel->relkind != RELKIND_RELATION
&& advise_rel->rd_rel->relkind != RELKIND_VIEW)
{
relation_close(advise_rel, AccessShareLock);

/* FIXME: add errdetail() and/or errcontext() calls here. */
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg( IND_ADV_ERROR_NTV )));
}

relation_close(advise_rel, AccessShareLock);
#else
/*
* heap_open() makes sure that the oid does not represent an INDEX or a
* COMPOSITE type, else it will raise an ERROR, which is exactly what we
* want. The comments above heap_open() ask the caller not to assume any
* storage since the returned relation may be a VIEW; but we don't mind,
* since the user may have defined some rules on it to make the INSERTs
* work smoothly! If not, we leave it upto the executor to raise ERROR.
*/
PG_TRY();
{
heap_close(heap_open(advise_oid, AccessShareLock), AccessShareLock);
}
PG_CATCH();
{
errmsg( IND_ADV_ERROR_NTV );
PG_RE_THROW();
}
PG_END_TRY();
#endif
}
else
{
/* FIXME: add errdetail() and/or errcontext() calls here. */
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg( IND_ADV_ERROR_NE )));
}

initStringInfo( &query );
initStringInfo( &cols );

foreach( cell, candidates ) /* foreach cell in candidates */
{
int i;
IndexCandidate* idxcd = (IndexCandidate*)lfirst( cell );
get_columnnames(idxcd);

if( !idxcd->idxused )
continue;

/* pfree() the memory allocated for the previous candidate. FIXME: Avoid
* meddling with the internals of a StringInfo, and try to use an API.
*/
if( cols.len > 0 )
{
pfree( cols.data );
cols.data = NULL;
}

appendStringInfo( &query, "select n_distintic from pg_stats where ");

for (i = 0; i < idxcd->ncols; ++i)
{

appendStringInfo( &cols, "attname=%s%d", (i>0?"OR":""),
idxcd->varattnombres[i]);

}/* foreach col in varattno*/

/* FIXME: Mention the column names explicitly after the table name. */
appendStringInfo( &query, "%s;", cols.data);

elog(INFO,"QUERY:%s", query.data);
elog(INFO,"LONGITUD:%d", query.len);

if( query.len > 0 ) /* if we generated any SQL */
{
if( SPI_connect() == SPI_OK_CONNECT )
{

if( SPI_execute( query.data, true, 0 ) != SPI_OK_SELECT )
elog( WARNING, "IND ADV: SPI_execute failed while select." );

else /* SPI_OK_SELECT*/
{

proc=SPI_processed;
tupdesc=SPI_tuptable->tupdesc;
SPITupleTable *tuptable=SPI_tuptable;
char buf[8192];
int i,j;
for(j=0;j<proc;j++)
{
/*cada fila*/
HeapTuple tuple=tuptable->vals[j];
for (i=0,buf[0]=0;i<tupdesc->natts;i++)
{
/* cada columna de cada fila*/
char *data;
data=SPI_getvalue(tuple,tupdesc,i);
/* falta imprimir data y guardar el dato correspondiente en la estructura
del índice*/
snprintf(buf+strlen(buf),sizeof(buf)-strlen(buf),"%s
%s",data,(i==tupdesc->natts)?"": "|");
}

elog(INFO,"EXECQ:%s",buf);
strcpy(idxcd->ndistinct,buf);

}

}

if( SPI_finish() != SPI_OK_FINISH )
elog( WARNING, "IND ADV: SPI_finish failed while select." );
}
else /* SPI_connect() != SPI_OK_CONNECT*/
elog( WARNING, "IND ADV: SPI_connect failed while select." );
}

/* TODO: Propose to -hackers to introduce API to free a StringInfoData . */
if ( query.len > 0 )
pfree( query.data );

} /* foreach cell in candidates */

elog( DEBUG3, "IND ADV: select: EXIT" );
}

static void
get_columnnames( IndexCandidate* idx )
{
int proc;
StringInfoData query; /* string for Query */
StringInfoData cols; /* string for Columns */
Oid advise_oid;
ListCell *cell;

SPITupleTable *SPI_tuptable;

TupleDesc tupdesc;

elog( DEBUG3, "IND ADV: get_column_names: ENTER" );

initStringInfo( &query );
initStringInfo( &cols );

int i;
IndexCandidate* idxcd = idx;

/* pfree() the memory allocated for the previous candidate. FIXME: Avoid
* meddling with the internals of a StringInfo, and try to use an API.
*/
if( cols.len > 0 )
{
pfree( cols.data );
cols.data = NULL;
} /*IF col.len>0*/

appendStringInfo( &query, "select a.attname from pg_class c,pg_attribute a
where c.oid=%d AND a.attrelid = c.oid AND ", idxcd->reloid);

for (i = 0; i < idxcd->ncols; ++i)
{

appendStringInfo( &cols, "a.attnum=%s%d", (i>0?"AND":""),
idxcd->varattno[i]);

}/* foreach col in varattno*/

/* FIXME: Mention the column names explicitly after the table name. */
appendStringInfo( &query, "%s;", cols.data);

elog(INFO,"QUERY:%s", query.data);
elog(INFO,"LONGITUD:%d", query.len);

if( query.len > 0 ) /* if we generated any SQL */
{
if( SPI_connect() == SPI_OK_CONNECT )
{

if( SPI_execute( query.data, true, 0 ) != SPI_OK_SELECT )
elog( WARNING, "IND ADV: SPI_execute failed while select." );

else /* ok*/
{

proc=SPI_processed;
tupdesc=SPI_tuptable->tupdesc;
SPITupleTable *tuptable=SPI_tuptable;
char buf[8192];
int i,j;
for(j=0;j<proc;j++)
{
/*cada fila*/
HeapTuple tuple=tuptable->vals[j];
for (i=0,buf[0]=0;i<tupdesc->natts;i++)
{
/* cada columna de cada fila*/
char *data;
data=SPI_getvalue(tuple,tupdesc,i);
idxcd->varattnombres[i]=data;

} /* (i=0,buf[0]=0;i<tupdesc->natts;i++)*/

}/* (j=0;j<proc;j++)*/

}/*else ok*/

if( SPI_finish() != SPI_OK_FINISH )
elog( WARNING, "IND ADV: SPI_finish failed while select." );

} /*if( SPI_connect() == SPI_OK_CONNECT )*/

else
elog( WARNING, "IND ADV: SPI_connect failed while select." );

} /*if( query.len > 0 )*/

/* TODO: Propose to -hackers to introduce API to free a StringInfoData . */
if ( query.len > 0 )
pfree( query.data );

elog( DEBUG3, "IND ADV: select: EXIT" );
}

El mar., 17 sept. 2019 a las 11:41, Yessica Brinkmann (<
yessica(dot)brinkmann(at)gmail(dot)com>) escribió:

> Muchas gracias a todos por sus respuestas. Voy a estar haciendo las
> verificaciones con el log, y enviando lo que me pidieron. Y también voy a
> enviar parte del código fuente, para que se pueda ver el Insert que
> funciona, y los Selects que quiero hacer.
> Saludos cordiales,
> Yessica
>
>
> El mar., 17 sept. 2019 9:57, Enrique Herrera Noya <
> enrique(dot)herreranoya(at)gmail(dot)com> escribió:
>
>>
>>
>> El mar., 17 de sep. de 2019 10:20, Yessica Brinkmann <
>> yessica(dot)brinkmann(at)gmail(dot)com> escribió:
>>
>>> El código fuente del SPI_connect ()? Si, estuve mirando. Pero sólo daba
>>> errores por error en la pila por lo que entendí. O sea, no encontré nada
>>> concreto de las posibles razones para un spi_error_connect.
>>> Saludos cordiales,
>>> Yessica
>>>
>>
>> Podrías hacer un diagrama, para entender la infraestructura como la
>> tienes estructurada,
>> De esa forma podremos ir acotando, cuál es el punto de falla,. Y de
>> acuerdo a eso ver LOG, Y saber que buscar
>>
>>
>>
>>
>>
>>>
>>> El mar., 17 sept. 2019 9:14, Enrique Herrera Noya <
>>> enrique(dot)herreranoya(at)gmail(dot)com> escribió:
>>>
>>>> miraste el código fuente?
>>>> ahí hay información que dejan los programadores...
>>>>
>>>>
>>>>
>>>> El mar., 17 de sep. de 2019 a la(s) 09:49, Yessica Brinkmann (
>>>> yessica(dot)brinkmann(at)gmail(dot)com) escribió:
>>>>
>>>>> No, realmente no creo que el error se deba a que se realiza "fuera del
>>>>> servidor". Permite realizar el Insert.
>>>>> Realmente justamente esa es mi pregunta... Si alguien conoce por qué
>>>>> podría dar error el SPI_connect (), o los motivos posibles para obtener un
>>>>> spi_error_connect con dicha función.
>>>>> Saludos cordiales,
>>>>> Yessica
>>>>>
>>>>> El mar., 17 sept. 2019 8:37, Enrique Herrera Noya <
>>>>> enrique(dot)herreranoya(at)gmail(dot)com> escribió:
>>>>>
>>>>>>
>>>>>>
>>>>>> El mar., 17 de sep. de 2019 a la(s) 08:52, Francisco Olarte (
>>>>>> folarte(at)peoplecall(dot)com) escribió:
>>>>>>
>>>>>>> Yessica:
>>>>>>>
>>>>>>> On Tue, Sep 17, 2019 at 12:40 PM Yessica Brinkmann
>>>>>>> <yessica(dot)brinkmann(at)gmail(dot)com> wrote:
>>>>>>> > Cuando digo en un programa me refiero a un programa en lenguaje C
>>>>>>> que se conecta al servidor Postgresql.
>>>>>>>
>>>>>>> Veamos, lenguaje aparte ( que aqui no importa, es el ABI simplemente
>>>>>>> ), no se si me he hecho entender.
>>>>>>>
>>>>>>> SPI quiere decir Server Programming Interface. Se usa para programar
>>>>>>> dentro del server, como si estuvieras haciendo las funciones en sql,
>>>>>>> o
>>>>>>> pl-sql. Es decir, para codigo que esta ejecutando en el server, no
>>>>>>> para "programas", que normalmente se usa para cosas que ejecutan
>>>>>>> FUERA
>>>>>>> del server y se hacen con la libpq, p.e., en C. De hecho no conectas
>>>>>>> con el servidor, la propia descripcion de la funcion dice
>>>>>>> "SPI_connect
>>>>>>> opens a connection from a C function invocation to the SPI manager.
>>>>>>> You must call this function if you want to execute commands through
>>>>>>> SPI. Some utility SPI functions can be called from unconnected C
>>>>>>> functions.", conectas con el manager, tienes que estar ya dentro del
>>>>>>> servidor ( por eso la funcion no tiene ningun parametro que diga
>>>>>>> donde
>>>>>>> esta el servidor ).
>>>>>>>
>>>>>>
>>>>>> entonces de acuerdo a eso, SPI_connect () daría error cuando se
>>>>>> intenta usar desde "fuera" del servidor?
>>>>>> siendo así , por que deja realizar INSERT según indica Yessica?
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>>
>>>>>>> > Pasa que estoy haciendo unas modificaciones al Index Adviser de
>>>>>>> Gurget como tesis de la Universidad, y para eso es.
>>>>>>> > El SPI_connect () se usa en dicho programa y funciona, para hacer
>>>>>>> un Insert. Yo estoy procurando de hacer Selects, pero supongo que debería
>>>>>>> funcionar igual.
>>>>>>> > Realmente no entiendo por qué me aparecería el spi_error_connect
>>>>>>>
>>>>>>> He intentado buscar el I.A. de G, en jujel sin exito. No se si es un
>>>>>>> programa / coleccion de o es un conjunto de funciones que se carga.
>>>>>>> Suponiendo que sea una extension, es raro que esa funcion de errores.
>>>>>>> ¿ Te has asegurado de que no llamas dos veces ? ¿ Has mirado el log
>>>>>>> del servidor a ver si dice algo ?
>>>>>>>
>>>>>>> Francisco Olarte.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> > Saludos cordiales,
>>>>>>> > Yessica
>>>>>>> >
>>>>>>> > El mar., 17 sept. 2019 6:08, Francisco Olarte <
>>>>>>> folarte(at)peoplecall(dot)com> escribió:
>>>>>>> >>
>>>>>>> >> Yessica:
>>>>>>> >>
>>>>>>> >> On Tue, Sep 17, 2019 at 11:39 AM Yessica Brinkmann
>>>>>>> >> <yessica(dot)brinkmann(at)gmail(dot)com> wrote:
>>>>>>> >> > Quisiera hacer una consulta al grupo por favor.
>>>>>>> >> > Alguien ha usado SPI_connect() para conectarse a Postgresql
>>>>>>> desde un programa?
>>>>>>> >> > Saben por si acaso en qué casos da error?
>>>>>>> >> > Me está dando error spi_error_connect desde un programa en C y
>>>>>>> no comprendo exactamente a qué se pueden deber los errores.
>>>>>>> >> > Disculpen la consulta pero es que hay muy poco información
>>>>>>> sobre el tema en Internet y muy pocos ejemplos. Prácticamente sólo está la
>>>>>>> documentación sobre el tema.
>>>>>>> >>
>>>>>>> >> Yo no la he usado, pero si que se que las SPI* son para ejecutar
>>>>>>> cosas
>>>>>>> >> desde una extension cargada en el servidor, desde una funcion que
>>>>>>> >> pones en una dll o similar y cargas en el servidor, como el
>>>>>>> postgis y
>>>>>>> >> similares.
>>>>>>> >>
>>>>>>> >> Cuando dices "en un programa" te refieres a eso o te refieres a un
>>>>>>> >> programa distinto, que se conecta al servidor ?
>>>>>>> >>
>>>>>>> >> Frnacisco Olarte.
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>
>>>>>> --
>>>>>> visita
>>>>>> http://www.plataformavecinal.cl
>>>>>> http://www.plataformaconstituyente.cl
>>>>>> http://www.partidopirata.cl
>>>>>> --
>>>>>> <http://www.partidopirata.cl>
>>>>>>
>>>>>
>>>>
>>>> --
>>>> visita
>>>> http://www.plataformavecinal.cl
>>>> http://www.plataformaconstituyente.cl
>>>> http://www.partidopirata.cl
>>>> --
>>>> <http://www.partidopirata.cl>
>>>>
>>>

Attachment Content-Type Size
gráfico - index - adviser.pdf application/pdf 26.3 KB

In response to

Responses

Browse pgsql-es-ayuda by date

  From Date Subject
Next Message Emanuel Calvo 2019-09-17 21:12:56 Re: PgBouncer con varias aplicaciones Java
Previous Message Yessica Brinkmann 2019-09-17 15:41:15 Re: SPI_connect