Yessica Brinkmann escribió: > Buenos días, > 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?
Hmm, si estás invocando tu función desde otra función que ya hace SPI_connect, entonces tienes que hacer SPI_push antes de invocar el SPI_connect, y un SPI_pop después del SPI_finish. Así creas un nuevo "contexto" para que SPI pueda procesar limpiamente tu consulta. Me parece que el ejemplo claro es que get_distinct está llamando a get_columnnames sin un SPI_push. Consejo aparte: no necesitas el snprintf con strlen etc; eso es lo que appendStringInfo() puede hacer por ti en forma más sencilla. (Para mostrar código fuente recomiendo ponerlo en un archivo adjunto en vez de copiar/pegar al mail, porque el programa de mail lo va a reformatear y queda ilegible. Para poder leer tu código tuve que pasarlo por pgindent ... va de vuelta como archivo adjunto.) Saludos -- Álvaro Herrera https://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Remote DBA, Training & Services
/** * 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."); } 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"); }