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 |
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 |