--- trunk/pgest.c 2005/05/26 19:42:36 20 +++ trunk/pgest.c 2005/07/08 12:47:49 38 @@ -34,248 +34,30 @@ #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp))) #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp))) +/* SortMem got renamed in PostgreSQL 8.0 */ +#ifndef SortMem + #define SortMem 16 * 1024 +#endif + /* prototype */ char *attr2text(ESTDOC *doc, char *attr); -ESTDB *db; -ESTCOND *cond; -ESTDOC *doc; -const CBLIST *texts; -int ecode, *est_result, resnum, i, j; -int limit = 0; -int offset = 0; - -/* define PostgreSQL v1 function */ -PG_FUNCTION_INFO_V1(pgest); -Datum pgest(PG_FUNCTION_ARGS) { - - FuncCallContext *funcctx; - int call_cntr; - int max_calls; - TupleDesc tupdesc; - TupleTableSlot *slot; - AttInMetadata *attinmeta; - char *index_path; - char *query; - char *attr; - - /* stuff done only on the first call of the function */ - if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; - - /* create a function context for cross-call persistence */ - funcctx = SRF_FIRSTCALL_INIT(); - - /* switch to memory context appropriate for multiple function calls */ - oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - /* take arguments from function */ - - /* index path */ - if (PG_ARGISNULL(0)) { - elog(ERROR, "index path can't be null"); - SRF_RETURN_DONE(funcctx); - } - index_path = _textout(PG_GETARG_TEXT_P(0)); - - /* query string */ - if (PG_ARGISNULL(0)) { - query = ""; - } else { - query = _textout(PG_GETARG_TEXT_P(1)); - } - - /* atribute filter */ - if (PG_ARGISNULL(2)) { - attr = ""; - } else { - attr = _textout(PG_GETARG_TEXT_P(2)); - } - - /* limit */ - if (PG_ARGISNULL(3)) { - limit = 0; - } else { - limit = PG_GETARG_INT32(3); - } - - /* offset */ - if (PG_ARGISNULL(4)) { - offset = 0; - } else { - offset = PG_GETARG_INT32(4); - } - - - /* open the database */ - elog(DEBUG1, "pgest: est_db_open(%s)", index_path); - - if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){ - elog(ERROR, "est_db_open: can't open %s [%d]: %s", index_path, ecode, est_err_msg(ecode)); - SRF_RETURN_DONE(funcctx); - } - - elog(DEBUG1, "pgest: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset); - - /* create a search condition object */ - if (!(cond = est_cond_new())) { - elog(INFO, "pgest: est_cond_new failed"); - SRF_RETURN_DONE(funcctx); - } - - /* set the search phrase to the search condition object */ - if (! PG_ARGISNULL(1) && strlen(query) > 0) - est_cond_set_phrase(cond, query); - - /* minimum valid attribute length is 10: @a STREQ a */ - if (! PG_ARGISNULL(2) && strlen(attr) >= 10) { - elog(DEBUG1,"est_cond_add_attr(%s)", attr); - est_cond_add_attr(cond, attr); - } - - /* get the result of search */ - est_result = est_db_search(db, cond, &resnum, NULL); - - /* total number of tuples to be returned */ - if (limit && limit < resnum) { - funcctx->max_calls = limit - offset; - } else { - funcctx->max_calls = resnum - offset; - } - - /* check if results exists */ - if ( 0 == funcctx->max_calls ) - elog(INFO, "pgest: no results for: %s", query ); - - elog(DEBUG1, "pgest: found %d hits for %s", resnum, query); - - /* Build a tuple description for a __pgest tuple */ - tupdesc = RelationNameGetTupleDesc("__pgest"); - - /* allocate a slot for a tuple with this tupdesc */ - slot = TupleDescGetSlot(tupdesc); - - /* assign slot to function context */ - funcctx->slot = slot; - - /* - * generate attribute metadata needed later to produce tuples from raw - * C strings - */ - attinmeta = TupleDescGetAttInMetadata(tupdesc); - funcctx->attinmeta = attinmeta; - - MemoryContextSwitchTo(oldcontext); - - elog(DEBUG1, "SRF_IS_FIRSTCALL done"); - } - - /* stuff done on every call of the function */ - funcctx = SRF_PERCALL_SETUP(); - - call_cntr = funcctx->call_cntr; - max_calls = funcctx->max_calls; - slot = funcctx->slot; - attinmeta = funcctx->attinmeta; - - if (limit && call_cntr > limit - 1) { - elog(DEBUG1, "call_cntr: %d limit: %d", call_cntr, limit); - SRF_RETURN_DONE(funcctx); - } - - if (call_cntr < max_calls) { - char **values; - HeapTuple tuple; - Datum result; - - elog(DEBUG1, "pgest: loop count %d", call_cntr); - - if (! est_result) { - elog(ERROR, "pgest: no estraier results"); - SRF_RETURN_DONE(funcctx); - } - - /* - * Prepare a values array for storage in our slot. - * This should be an array of C strings which will - * be processed later by the type input functions. - */ - - if (doc = est_db_get_doc(db, est_result[call_cntr + offset], 0)) { - - elog(DEBUG1, "URI: %s\n Title: %s\n", - est_doc_attr(doc, "@uri"), - est_doc_attr(doc, "@title") - ); - - values = (char **) palloc(4 * sizeof(char *)); - -// values[0] = (char *) palloc(strlen(_estval) * sizeof(char)); - - values[0] = (char *) attr2text(doc,"@id"); - values[1] = (char *) attr2text(doc,"@uri"); - values[2] = (char *) attr2text(doc,"@title"); - values[3] = (char *) attr2text(doc,"@size"); - - /* destloy the document object */ - elog(DEBUG2, "est_doc_delete"); - est_doc_delete(doc); - } else { - elog(INFO, "no result from estraier"); - values[0] = DatumGetCString( "" ); - values[1] = DatumGetCString( "" ); - values[2] = DatumGetCString( "" ); - values[3] = DatumGetCString( "" ); - } - - - elog(DEBUG2, "build tuple"); - /* build a tuple */ - tuple = BuildTupleFromCStrings(attinmeta, values); - - elog(DEBUG2, "make tuple into datum"); - /* make the tuple into a datum */ - result = TupleGetDatum(slot, tuple); - - elog(DEBUG2, "cleanup"); - /* clean up ? */ -/* - pfree(values[0]); - pfree(values[1]); - pfree(values[2]); - pfree(values[3]); - pfree(values); -*/ - - elog(DEBUG2, "cleanup over"); - - SRF_RETURN_NEXT(funcctx, result); - } else { - elog(DEBUG1, "loop over"); - - if(!est_db_close(db, &ecode)){ - elog(INFO, "est_db_close error: %s", est_err_msg(ecode)); - } - - /* do when there is no more left */ - SRF_RETURN_DONE(funcctx); - } -} /* work in progress */ PG_FUNCTION_INFO_V1(pgest_attr); Datum pgest_attr(PG_FUNCTION_ARGS) { - ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(5); - Oid element_type = ARR_ELEMTYPE(attr_arr); - int ndims = ARR_NDIM(attr_arr); - int *dim_counts = ARR_DIMS(attr_arr); - int *dim_lower_bounds = ARR_LBOUND(attr_arr); + ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(6); + Oid attr_element_type = ARR_ELEMTYPE(attr_arr); + int attr_ndims = ARR_NDIM(attr_arr); + int *attr_dim_counts = ARR_DIMS(attr_arr); + int *attr_dim_lower_bounds = ARR_LBOUND(attr_arr); int ncols = 0; int nrows = 0; int indx[MAXDIM]; - int16 typlen; - bool typbyval; - char typalign; + int16 attr_len; + bool attr_byval; + char attr_align; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; AttInMetadata *attinmeta; TupleDesc tupdesc; @@ -288,15 +70,24 @@ int rsinfo_ncols; int i, j; /* estvars */ + ESTDB *db; + ESTCOND *cond; + ESTDOC *doc; + const CBLIST *texts; + int ecode, *est_result, resnum; + int limit = 0; + int offset = 0; + char *index_path; char *query; char *attr; + char *order; /* only allow 1D input array */ - if (ndims == 1) + if (attr_ndims == 1) { - ncols = dim_counts[0]; + ncols = attr_dim_counts[0]; } else ereport(ERROR, @@ -312,7 +103,7 @@ "allowed in this context"))); /* get info about element type needed to construct the array */ - get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align); /* get the requested return tuple description */ tupdesc = rsinfo->expectedDesc; @@ -353,7 +144,7 @@ index_path = _textout(PG_GETARG_TEXT_P(0)); /* query string */ - if (PG_ARGISNULL(0)) { + if (PG_ARGISNULL(1)) { query = ""; } else { query = _textout(PG_GETARG_TEXT_P(1)); @@ -365,19 +156,27 @@ } else { attr = _textout(PG_GETARG_TEXT_P(2)); } + + /* sort order */ + if (PG_ARGISNULL(3)) { + order = ""; + } else { + order = _textout(PG_GETARG_TEXT_P(3)); + } + /* limit */ - if (PG_ARGISNULL(3)) { + if (PG_ARGISNULL(4)) { limit = 0; } else { - limit = PG_GETARG_INT32(3); + limit = PG_GETARG_INT32(4); } /* offset */ - if (PG_ARGISNULL(4)) { + if (PG_ARGISNULL(5)) { offset = 0; } else { - offset = PG_GETARG_INT32(4); + offset = PG_GETARG_INT32(5); } @@ -408,6 +207,17 @@ est_cond_add_attr(cond, attr); } + /* set the search phrase to the search condition object */ + if (! PG_ARGISNULL(3) && strlen(order) > 0) { + elog(DEBUG1,"est_cond_set_order(%s)", order); + est_cond_set_order(cond, order); + } + + if (limit) { + elog(DEBUG1,"est_cond_set_max(%d)", limit + offset); + est_cond_set_max(cond, limit + offset); + } + /* get the result of search */ est_result = est_db_search(db, cond, &resnum, NULL); @@ -418,7 +228,8 @@ /* total number of tuples to be returned */ if (limit && limit < resnum) { - nrows = limit - offset; + nrows = limit; + elog(INFO, "This is probably a bug in limit implementation. Please report it to dpavlin@rot13.org"); } else { nrows = resnum - offset; } @@ -448,9 +259,9 @@ bool isnull; /* array value of this position */ - indx[0] = j + dim_lower_bounds[0]; + indx[0] = j + attr_dim_lower_bounds[0]; - dvalue = array_ref(attr_arr, ndims, indx, -1, typlen, typbyval, typalign, &isnull); + dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull); if (!isnull && doc) values[j] = DatumGetCString( @@ -484,6 +295,8 @@ rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); + est_cond_delete(cond); + if(!est_db_close(db, &ecode)){ ereport(ERROR, (errcode(ERRCODE_IO_ERROR), errmsg("est_db_close: %d", ecode),