--- trunk/pgswish.c 2005/02/20 21:51:56 16 +++ trunk/pgswish.c 2005/05/29 20:30:18 20 @@ -6,6 +6,8 @@ * TODO: * - check null input using PG_ARGISNULL before using PG_GETARG_xxxx * - support composite type arguments + * - split error_or_abort + * - use getResultPropValue not SwishResultPropertyStr * * NOTES: * - clear structures with memset to support hash indexes (who whould like @@ -34,11 +36,11 @@ #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp))) - -SW_HANDLE swish_handle = NULL;/* Database handle */ -SW_SEARCH search = NULL; /* search handle -- holds search parameters */ -SW_RESULTS swish_results = NULL; /* results handle -- holds list of results */ -SW_RESULT *sw_res = NULL; /* one row from swish-e results */ +/* Globals */ +static SW_HANDLE swish_handle = NULL; /* Database handle */ +static SW_SEARCH search = NULL; /* search handle -- search parameters */ +static SW_RESULTS swish_results = NULL; /* results handle -- list of results */ +static SW_RESULT *sw_res = NULL; /* one row from swish-e results */ /* define PostgreSQL v1 function */ PG_FUNCTION_INFO_V1(pgswish); @@ -52,6 +54,7 @@ AttInMetadata *attinmeta; char *index_path; char *query; + FILE *logfh; /* stuff done only on the first call of the function */ if (SRF_IS_FIRSTCALL()) { @@ -69,27 +72,41 @@ oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /* Send any errors or warnings to stderr (default is stdout) */ - SwishErrorsToStderr(); + /* Send any errors or warnings to log, as well as + * STDOUT and STDERR (just to be sure) */ + if ( logfh = fopen("/tmp/pgswish.log", "a") ) { + set_error_handle( logfh ); + elog(INFO, "loggin swish-e errors to /tmp/pgswish.log"); + /* redirect STDOUT and STDERR to log */ + dup2(1, logfh); + dup2(2, logfh); + } else { + elog(INFO, "can't open /tmp/pgswish.log -- errors from swish-e won't be cought and may result in back-end crashes!"); + } elog(INFO, "pgswish: SwishInit(%s)", index_path); - + swish_handle = SwishInit( index_path ); + if ( SwishError( swish_handle ) ) + elog(INFO, "pgswish: SwishInit(%s) failed: %s", index_path, SwishErrorString( swish_handle )); + + elog(INFO, "handle: %08x", swish_handle); + if (! swish_handle) { elog(ERROR, "pgswish: can't open %s", index_path); SRF_RETURN_DONE(funcctx); } - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) SRF_RETURN_DONE(funcctx); /* set ranking scheme. default is 0 */ SwishRankScheme( swish_handle, 0 ); - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) SRF_RETURN_DONE(funcctx); elog(INFO, "pgswish: SwishQuery(%s)", query); /* Here's a short-cut to searching that creates a search object and searches at the same time */ swish_results = SwishQuery( swish_handle, query); - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) SRF_RETURN_DONE(funcctx); /* total number of tuples to be returned */ funcctx->max_calls = SwishHits( swish_results ); @@ -142,7 +159,7 @@ } elog(DEBUG1, "pgswish: check for swish-e error"); - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) SRF_RETURN_DONE(funcctx); /* * Prepare a values array for storage in our slot. @@ -153,6 +170,8 @@ sw_res = SwishNextResult( swish_results ); if (! sw_res) { elog(ERROR, "pgswish: swish-e sort result list: %d rows expected %d", call_cntr, max_calls - 1); + Free_Results_Object( swish_results ); + Free_Search_Object( search ); SRF_RETURN_DONE(funcctx); } @@ -198,7 +217,7 @@ pfree(values[3]); pfree(values); - elog(INFO, "row: %s|%s|%s|%s",values[0],values[1],values[2],values[3]); + elog(DEBUG1, "row: %s|%s|%s|%s",values[0],values[1],values[2],values[3]); SRF_RETURN_NEXT(funcctx, result); } else { @@ -213,113 +232,32 @@ } } -/* work in progress */ -PG_FUNCTION_INFO_V1(pgswish2); -Datum pgswish2(PG_FUNCTION_ARGS) -{ - int ncols = 2; - int nrows = 3; - int16 typlen; - bool typbyval; - char typalign; - ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; - AttInMetadata *attinmeta; - TupleDesc tupdesc; - Tuplestorestate *tupstore = NULL; - HeapTuple tuple; - MemoryContext per_query_ctx; - MemoryContext oldcontext; - Datum dvalue; - char **values; - int rsinfo_ncols; - int i, j; - - /* check to see if caller supports us returning a tuplestore */ - if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize)) - ereport(ERROR, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("materialize mode required, but it is not " \ - "allowed in this context"))); - - /* get the requested return tuple description */ - tupdesc = rsinfo->expectedDesc; - rsinfo_ncols = tupdesc->natts; - - /* - * The requested tuple description better match up with the array - * we were given. - */ - elog(INFO, "rsinfo_ncols = %d, ncols = %d", rsinfo_ncols, ncols); - - /* OK, use it */ - attinmeta = TupleDescGetAttInMetadata(tupdesc); - - /* Now go to work */ - rsinfo->returnMode = SFRM_Materialize; - - per_query_ctx = fcinfo->flinfo->fn_mcxt; - oldcontext = MemoryContextSwitchTo(per_query_ctx); - - /* initialize our tuplestore */ - tupstore = tuplestore_begin_heap(true, false, SortMem); - - values = (char **) palloc(ncols * sizeof(char *)); - - for (i = 0; i < nrows; i++) - { - for (j = 0; j < ncols; j++) - { - values[j] = DatumGetCString( "foo" ); - } - /* construct the tuple */ - tuple = BuildTupleFromCStrings(attinmeta, values); - - /* now store it */ - tuplestore_puttuple(tupstore, tuple); - } - - tuplestore_donestoring(tupstore); - rsinfo->setResult = tupstore; - - /* - * SFRM_Materialize mode expects us to return a NULL Datum. The actual - * tuples are in our tuplestore and passed back through - * rsinfo->setResult. rsinfo->setDesc is set to the tuple description - * that we actually used to build our tuples with, so the caller can - * verify we did what it was expecting. - */ - rsinfo->setDesc = tupdesc; - MemoryContextSwitchTo(oldcontext); - - return (Datum) 0; -} - -/* make text var prom property */ +/* make text var from property */ char *prop2text(SW_RESULT sw_res, char *propname) { char *val; char *prop; int len; - elog(DEBUG1, "prop2text(%s)", propname); + elog(DEBUG2, "prop2text(%s)", propname); prop = SwishResultPropertyStr( sw_res, propname ); - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) return NULL; len = strlen(prop); - elog(INFO, "prop2text(%s) = '%s' %d bytes", propname, prop, len); + elog(DEBUG1, "prop2text(%s) = '%s' %d bytes", propname, prop, len); len++; len *= sizeof(char); - elog(DEBUG1, "palloc(%d)", len); + elog(DEBUG2, "palloc(%d)", len); val = palloc(len); memset(val, 0, len); strncpy(val, prop, len); - elog(DEBUG1, "val=%s", val); + elog(DEBUG2, "val=%s", val); return val; } @@ -330,22 +268,22 @@ unsigned long prop; int len; - elog(DEBUG1, "prop2int(%s)", propname); + elog(DEBUG2, "prop2int(%s)", propname); prop = SwishResultPropertyULong( sw_res, propname ); - error_or_abort( swish_handle ); + if (error_or_abort( swish_handle )) return NULL; - elog(INFO, "prop2int(%s) = %lu", propname, prop); + elog(DEBUG1, "prop2int(%s) = %lu", propname, prop); len = 128 * sizeof(char); - elog(DEBUG1, "palloc(%d)", len); + elog(DEBUG2, "palloc(%d)", len); val = palloc(len); memset(val, 0, len); snprintf(val, len, "%lu", prop); - elog(DEBUG1, "val=%s", val); + elog(DEBUG2, "val=%s", val); return val; } @@ -354,9 +292,9 @@ /* * check if swish has returned error, and elog it. */ -static void error_or_abort( SW_HANDLE swish_handle ) { +static int error_or_abort( SW_HANDLE swish_handle ) { if ( !SwishError( swish_handle ) ) - return; + return 0; /* print a message */ elog(ERROR, @@ -365,7 +303,10 @@ SwishErrorString( swish_handle ), SwishLastErrorMsg( swish_handle ) ); + if ( swish_results ) Free_Results_Object( swish_results ); if ( search ) Free_Search_Object( search ); SwishClose( swish_handle ); + + return 1; }