--- trunk/pgest.c 2005/05/22 21:18:11 9 +++ trunk/pgest.c 2005/05/26 17:56:53 19 @@ -63,19 +63,48 @@ if (SRF_IS_FIRSTCALL()) { MemoryContext oldcontext; - /* take arguments from function */ - //index_path = _textout(PG_GETARG_TEXT_P(0)); - index_path = _textout(PG_GETARG_TEXT_P(0)); - query = _textout(PG_GETARG_TEXT_P(1)); - attr = _textout(PG_GETARG_TEXT_P(2)); - limit = PG_GETARG_INT32(3); - offset = PG_GETARG_INT32(4); - /* 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); @@ -85,7 +114,7 @@ SRF_RETURN_DONE(funcctx); } - elog(INFO, "pgest: query[%s] attr[%s] limit %d offset %d", query, attr, limit, offset); + elog(INFO, "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())) { @@ -94,11 +123,11 @@ } /* set the search phrase to the search condition object */ - if (strlen(query) > 0) + if (! PG_ARGISNULL(1) && strlen(query) > 0) est_cond_set_phrase(cond, query); /* minimum valid attribute length is 10: @a STREQ a */ - if (attr != NULL && strlen(attr) >= 10) { + if (! PG_ARGISNULL(2) && strlen(attr) >= 10) { elog(INFO,"est_cond_add_attr(%s)", attr); est_cond_add_attr(cond, attr); } @@ -185,7 +214,7 @@ values[0] = (char *) attr2text(doc,"@id"); values[1] = (char *) attr2text(doc,"@uri"); values[2] = (char *) attr2text(doc,"@title"); - values[3] = (char *) attr2text(doc,"@type"); + values[3] = (char *) attr2text(doc,"@size"); /* destloy the document object */ elog(DEBUG2, "est_doc_delete"); @@ -233,25 +262,48 @@ } /* work in progress */ -PG_FUNCTION_INFO_V1(pgest2); -Datum pgest2(PG_FUNCTION_ARGS) +PG_FUNCTION_INFO_V1(pgest_attr); +Datum pgest_attr(PG_FUNCTION_ARGS) { - int nrows = 3; + 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); + int ncols = 0; + int nrows = 0; + int indx[MAXDIM]; int16 typlen; bool typbyval; char typalign; ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; AttInMetadata *attinmeta; TupleDesc tupdesc; - Tuplestorestate *tupstore = NULL; + Tuplestorestate *tupstore = NULL; HeapTuple tuple; MemoryContext per_query_ctx; MemoryContext oldcontext; Datum dvalue; char **values; - int ncols; + int rsinfo_ncols; int i, j; + /* estvars */ + char *index_path; + char *query; + char *attr; + + /* only allow 1D input array */ + if (ndims == 1) + { + ncols = dim_counts[0]; + } + else + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid input array"), + errdetail("Input array must have 1 dimension"))); + /* check to see if caller supports us returning a tuplestore */ if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize)) ereport(ERROR, @@ -259,14 +311,23 @@ errmsg("materialize mode required, but it is not " \ "allowed in this context"))); + /* get info about element type needed to construct the array */ + get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign); + /* get the requested return tuple description */ tupdesc = rsinfo->expectedDesc; - ncols = tupdesc->natts; + rsinfo_ncols = tupdesc->natts; /* * The requested tuple description better match up with the array * we were given. */ + if (rsinfo_ncols != ncols) + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("invalid input array"), + errdetail("Number of elements in array must match number of query specified columns."))); + /* OK, use it */ attinmeta = TupleDescGetAttInMetadata(tupdesc); @@ -279,19 +340,135 @@ /* initialize our tuplestore */ tupstore = tuplestore_begin_heap(true, false, SortMem); + + /* take rest of arguments from function */ + + /* index path */ + if (PG_ARGISNULL(0)) { + ereport(ERROR, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("index path can't be null"), + errdetail("Index path must be valid full path to HyperEstraier index"))); + } + 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_attr: est_db_open(%s)", index_path); + + if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){ + ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("est_db_open: can't open %s: %d", index_path, ecode), + errdetail(est_err_msg(ecode)))); + } + + elog(INFO, "pgest_attr: 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())) { + ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED), + errmsg("pgest_attr: est_cond_new failed"))); + } + + /* 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(INFO,"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); + + /* check if results exists */ + if ( 0 == resnum ) { + elog(INFO, "pgest_attr: no results for: %s", query ); + } + + /* total number of tuples to be returned */ + if (limit && limit < resnum) { + nrows = limit - offset; + } else { + nrows = resnum - offset; + } + + + elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query); + + values = (char **) palloc(ncols * sizeof(char *)); for (i = 0; i < nrows; i++) { + + /* get result from estraier */ + if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) { + elog(INFO, "can't find result %d", i + offset); + } else { + elog(DEBUG1, "URI: %s\n Title: %s\n", + est_doc_attr(doc, "@uri"), + est_doc_attr(doc, "@title") + ); + } + + /* iterate over results */ for (j = 0; j < ncols; j++) { - values[j] = DatumGetCString( "foo" ); + bool isnull; + + /* array value of this position */ + indx[0] = j + dim_lower_bounds[0]; + + dvalue = array_ref(attr_arr, ndims, indx, -1, typlen, typbyval, typalign, &isnull); + + if (!isnull && doc) + values[j] = DatumGetCString( + attr2text(doc, + DirectFunctionCall1(textout, dvalue) + )); + else + values[j] = NULL; } /* construct the tuple */ tuple = BuildTupleFromCStrings(attinmeta, values); /* now store it */ tuplestore_puttuple(tupstore, tuple); + + + /* delete estraier document object */ + est_doc_delete(doc); } tuplestore_donestoring(tupstore); @@ -307,6 +484,12 @@ rsinfo->setDesc = tupdesc; MemoryContextSwitchTo(oldcontext); + if(!est_db_close(db, &ecode)){ + ereport(ERROR, (errcode(ERRCODE_IO_ERROR), + errmsg("est_db_close: %d", ecode), + errdetail(est_err_msg(ecode)))); + } + return (Datum) 0; } @@ -344,30 +527,3 @@ return val; } -/* make integer variable from property */ -/* -char *prop2int(SW_RESULT sw_res, char *propname) { - char *val; - unsigned long prop; - int len; - - elog(DEBUG2, "prop2int(%s)", propname); - - prop = estResultPropertyULong( sw_res, propname ); - if (error_or_abort( est_handle )) return NULL; - - elog(DEBUG1, "prop2int(%s) = %lu", propname, prop); - - len = 128 * sizeof(char); - elog(DEBUG2, "palloc(%d)", len); - - val = palloc(len); - memset(val, 0, len); - - snprintf(val, len, "%lu", prop); - - elog(DEBUG2, "val=%s", val); - - return val; -} -*/