/[pgestraier]/trunk/pgest.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/pgest.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 5 by dpavlin, Fri May 20 19:44:09 2005 UTC revision 40 by dpavlin, Sat Sep 10 18:51:13 2005 UTC
# Line 34  Line 34 
34  #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))  #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
35  #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))  #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
36    
37    /* SortMem got renamed in PostgreSQL 8.0 */
38    #ifndef SortMem
39     #define SortMem 16 * 1024
40    #endif
41    
42    #define ATTR_DELIMITER "{{!}}"
43    
44  /* prototype */  /* prototype */
45  char *attr2text(ESTDOC *doc, char *attr);  char *attr2text(ESTDOC *doc, char *attr);
46    
47  ESTDB *db;  
48  ESTCOND *cond;  /* work in progress */
49  ESTDOC *doc;  PG_FUNCTION_INFO_V1(pgest_attr);
50  const CBLIST *texts;  Datum pgest_attr(PG_FUNCTION_ARGS)
51  int ecode, *est_result, resnum, i, j;  {
52  int limit = 0;          ArrayType       *attr_arr = PG_GETARG_ARRAYTYPE_P(6);
53  int offset = 0;          Oid             attr_element_type = ARR_ELEMTYPE(attr_arr);
54            int             attr_ndims = ARR_NDIM(attr_arr);
55  /* define PostgreSQL v1 function */          int             *attr_dim_counts = ARR_DIMS(attr_arr);
56  PG_FUNCTION_INFO_V1(pgest);          int             *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
57  Datum pgest(PG_FUNCTION_ARGS) {          int             ncols = 0;
58            int             nrows = 0;
59          FuncCallContext *funcctx;          int             indx[MAXDIM];
60          int             call_cntr;          int16           attr_len;
61          int             max_calls;          bool            attr_byval;
62          TupleDesc       tupdesc;          char            attr_align;
63          TupleTableSlot  *slot;          ReturnSetInfo   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
64          AttInMetadata   *attinmeta;          AttInMetadata   *attinmeta;
65            TupleDesc       tupdesc;
66            Tuplestorestate *tupstore = NULL;
67            HeapTuple       tuple;
68            MemoryContext   per_query_ctx;
69            MemoryContext   oldcontext;
70            Datum           dvalue;
71            char            **values;
72            int             rsinfo_ncols;
73            int             i, j;
74            /* estvars */
75            ESTDB *db;
76            ESTCOND *cond;
77            ESTDOC *doc;
78            const CBLIST *texts;
79            int ecode, *est_result, resnum;
80            int limit = 0;
81            int offset = 0;
82    
83          char            *index_path;          char            *index_path;
84          char            *query;          char            *query;
85          char            *attr;          char            *attr;
86            char            *order;
87    
         /* stuff done only on the first call of the function */  
         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();  
88    
89                  /* switch to memory context appropriate for multiple function calls */          /* only allow 1D input array */
90                  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);          if (attr_ndims == 1)
91            {
92                  /* open the database */                  ncols = attr_dim_counts[0];
93                  elog(DEBUG1, "pgest: est_db_open(%s)", index_path);          }
94                            else
95                  if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){                  ereport(ERROR,
96                          elog(ERROR, "est_db_open: can't open %s [%d]: %s", index_path, ecode, est_err_msg(ecode));                                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
97                          SRF_RETURN_DONE(funcctx);                                   errmsg("invalid input array"),
98                  }                                   errdetail("Input array must have 1 dimension")));
                   
                 elog(INFO, "pgest: query[%s] attr[%s] limit %d offset %d", query, attr, limit, offset);  
                   
                 /* create a search condition object */  
                 if (!(cond = est_cond_new())) {  
                         elog(INFO, "pgest: est_cond_new failed");  
                         SRF_RETURN_DONE(funcctx);  
                 }  
99                                    
100                  /* set the search phrase to the search condition object */          /* check to see if caller supports us returning a tuplestore */
101                  est_cond_set_phrase(cond, query);          if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
102                    ereport(ERROR,
103                                    (errcode(ERRCODE_SYNTAX_ERROR),
104                                     errmsg("materialize mode required, but it is not " \
105                                                    "allowed in this context")));
106    
107                  /* minimum valid attribute length is 10: @a STREQ a */          /* get info about element type needed to construct the array */
108                  if (attr != NULL && strlen(attr) >= 10) {          get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
                         elog(INFO,"est_cond_add_attr(%s)", attr);  
                         est_cond_add_attr(cond, attr);  
                 }  
109    
110                  /* get the result of search */          /* get the requested return tuple description */
111                  est_result = est_db_search(db, cond, &resnum, NULL);          tupdesc = rsinfo->expectedDesc;
112                            rsinfo_ncols = tupdesc->natts;
                 /* total number of tuples to be returned */  
                 if (limit && limit < resnum) {  
                         funcctx->max_calls = limit - offset;  
                 } else {  
                         funcctx->max_calls = resnum - offset;  
                 }  
113    
114                  /* check if results exists */          /*
115                  if ( 0 == funcctx->max_calls )           * The requested tuple description better match up with the array
116                          elog(INFO, "pgest: no results for: %s", query );           * we were given.
117             */
118            if (rsinfo_ncols != ncols)
119                    ereport(ERROR,
120                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
121                                     errmsg("invalid input array"),
122                                     errdetail("Number of elements in array must match number of query specified columns.")));
123    
124                  elog(DEBUG1, "pgest: found %d hits for %s", resnum, query);          /* OK, use it */
125            attinmeta = TupleDescGetAttInMetadata(tupdesc);
126    
127                  /* Build a tuple description for a __pgest tuple */          /* Now go to work */
128                  tupdesc = RelationNameGetTupleDesc("__pgest");          rsinfo->returnMode = SFRM_Materialize;
129    
130                  /* allocate a slot for a tuple with this tupdesc */          per_query_ctx = fcinfo->flinfo->fn_mcxt;
131                  slot = TupleDescGetSlot(tupdesc);          oldcontext = MemoryContextSwitchTo(per_query_ctx);
132    
133                  /* assign slot to function context */          /* initialize our tuplestore */
134                  funcctx->slot = slot;          tupstore = tuplestore_begin_heap(true, false, SortMem);
135    
                 /*  
                  * generate attribute metadata needed later to produce tuples from raw  
                  * C strings  
                  */  
                 attinmeta = TupleDescGetAttInMetadata(tupdesc);  
                 funcctx->attinmeta = attinmeta;  
136    
137                  MemoryContextSwitchTo(oldcontext);          /* take rest of arguments from function */
138    
139                  elog(DEBUG1, "SRF_IS_FIRSTCALL done");          /* index path */
140            if (PG_ARGISNULL(0)) {
141                    ereport(ERROR,
142                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
143                                     errmsg("index path can't be null"),
144                                     errdetail("Index path must be valid full path to HyperEstraier index")));
145          }          }
146            index_path = _textout(PG_GETARG_TEXT_P(0));
147    
148          /* stuff done on every call of the function */          /* query string */
149          funcctx = SRF_PERCALL_SETUP();          if (PG_ARGISNULL(1)) {
150                    query = "";
151          call_cntr = funcctx->call_cntr;          } else {
152          max_calls = funcctx->max_calls;                  query = _textout(PG_GETARG_TEXT_P(1));
         slot = funcctx->slot;  
         attinmeta = funcctx->attinmeta;  
   
         if (limit && call_cntr > limit - 1) {  
                 elog(INFO, "call_cntr: %d limit: %d", call_cntr, limit);  
                 SRF_RETURN_DONE(funcctx);  
153          }          }
154    
155          if (call_cntr < max_calls) {          /* atribute filter */
156                  char            **values;          if (PG_ARGISNULL(2)) {
157                  HeapTuple       tuple;                  attr = "";
158                  Datum           result;          } else {
159                    attr = _textout(PG_GETARG_TEXT_P(2));
160                  elog(DEBUG1, "pgest: loop count %d", call_cntr);          }
161            
162                  if (! est_result) {          /* sort order */
163                          elog(ERROR, "pgest: no estraier results");          if (PG_ARGISNULL(3)) {
164                          SRF_RETURN_DONE(funcctx);                  order = "";
165                  }          } else {
166                                    order = _textout(PG_GETARG_TEXT_P(3));
167                  /*          }
                  * 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 *));  
168    
 //                      values[0] = (char *) palloc(strlen(_estval) * sizeof(char));  
169    
170                          values[0] = (char *) attr2text(doc,"@id");          /* limit */
171                          values[1] = (char *) attr2text(doc,"@uri");          if (PG_ARGISNULL(4)) {
172                          values[2] = (char *) attr2text(doc,"@title");                  limit = 0;
173                          values[3] = (char *) attr2text(doc,"@type");          } else {
174                    limit = PG_GETARG_INT32(4);
175                          /* destloy the document object */          }
                         elog(DEBUG2, "est_doc_delete");  
                         est_doc_delete(doc);  
                 } else {  
                         elog(INFO, "no result from estraier");  
                         values[0] = NULL;  
                         values[1] = NULL;  
                         values[2] = NULL;  
                         values[3] = NULL;  
                 }  
176    
177            /* offset */
178            if (PG_ARGISNULL(5)) {
179                    offset = 0;
180            } else {
181                    offset = PG_GETARG_INT32(5);
182            }
183    
                 elog(DEBUG2, "build tuple");  
                 /* build a tuple */  
                 tuple = BuildTupleFromCStrings(attinmeta, values);  
184    
185                  elog(DEBUG2, "make tuple into datum");          /* open the database */
186                  /* make the tuple into a datum */          elog(DEBUG1, "pgest_attr: est_db_open(%s)", index_path);
187                  result = TupleGetDatum(slot, tuple);                  
188            if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){
189                  elog(DEBUG2, "cleanup");                  ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
190                  /* clean up ? */                          errmsg("est_db_open: can't open %s: %d", index_path, ecode),
191  /*                          errdetail(est_err_msg(ecode))));
192                  pfree(values[0]);          }
                 pfree(values[1]);  
                 pfree(values[2]);  
                 pfree(values[3]);  
                 pfree(values);  
 */  
193                                    
194                  elog(DEBUG2, "cleanup over");          elog(DEBUG1, "pgest_attr: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset);
195                    
196                  SRF_RETURN_NEXT(funcctx, result);          /* create a search condition object */
197          } else {          if (!(cond = est_cond_new())) {
198                  elog(DEBUG1, "loop over");                  ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
199                            errmsg("pgest_attr: est_cond_new failed")));
200            }
201            
202            /* set the search phrase to the search condition object */
203            if (! PG_ARGISNULL(1) && strlen(query) > 0)
204                    est_cond_set_phrase(cond, query);
205    
206                  if(!est_db_close(db, &ecode)){          /* minimum valid attribute length is 10: @a STREQ a */
207                          elog(INFO, "est_db_close error: %s", est_err_msg(ecode));          if (! PG_ARGISNULL(2) && strlen(attr) >= 10) {
208                    elog(DEBUG1,"attributes: %s", attr);
209                    char *curr_attr;
210                    curr_attr = strtok(attr, ATTR_DELIMITER);
211                    while (curr_attr) {
212                            elog(DEBUG1,"est_cond_add_attr(%s)", curr_attr);
213                            est_cond_add_attr(cond, curr_attr);
214                            curr_attr = strtok(NULL, ATTR_DELIMITER);
215                  }                  }
216            }
217    
218                  /* do when there is no more left */          /* set the search phrase to the search condition object */
219                  SRF_RETURN_DONE(funcctx);          if (! PG_ARGISNULL(3) && strlen(order) > 0) {
220                    elog(DEBUG1,"est_cond_set_order(%s)", order);
221                    est_cond_set_order(cond, order);
222          }          }
 }  
223    
224  /* work in progress */          if (limit) {
225  PG_FUNCTION_INFO_V1(pgest2);                  elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
226  Datum pgest2(PG_FUNCTION_ARGS)                  est_cond_set_max(cond, limit + offset);
227  {          }
         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             ncols;  
         int             i, j;  
228    
229          /* check to see if caller supports us returning a tuplestore */          /* get the result of search */
230          if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))          est_result = est_db_search(db, cond, &resnum, NULL);
                 ereport(ERROR,  
                                 (errcode(ERRCODE_SYNTAX_ERROR),  
                                  errmsg("materialize mode required, but it is not " \  
                                                 "allowed in this context")));  
231    
232          /* get the requested return tuple description */          /* check if results exists */
233          tupdesc = rsinfo->expectedDesc;          if ( 0 == resnum ) {
234          ncols = tupdesc->natts;                  elog(INFO, "pgest_attr: no results for: %s", query );
235            }
236    
237          /*          /* total number of tuples to be returned */
238           * The requested tuple description better match up with the array          if (limit && limit < resnum) {
239           * we were given.                  nrows = limit;
240           */          } else {
241          /* OK, use it */                  nrows = resnum - offset;
242          attinmeta = TupleDescGetAttInMetadata(tupdesc);          }
243    
         /* Now go to work */  
         rsinfo->returnMode = SFRM_Materialize;  
244    
245          per_query_ctx = fcinfo->flinfo->fn_mcxt;          elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);
         oldcontext = MemoryContextSwitchTo(per_query_ctx);  
246    
         /* initialize our tuplestore */  
         tupstore = tuplestore_begin_heap(true, false, SortMem);  
247    
248          values = (char **) palloc(ncols * sizeof(char *));          values = (char **) palloc(ncols * sizeof(char *));
249    
250          for (i = 0; i < nrows; i++)          for (i = 0; i < nrows; i++)
251          {          {
252    
253                    /* get result from estraier */
254                    if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {
255                            elog(INFO, "can't find result %d", i + offset);
256                    } else {
257                            elog(DEBUG1, "URI: %s\n Title: %s\n",
258                                    est_doc_attr(doc, "@uri"),
259                                    est_doc_attr(doc, "@title")
260                            );
261                    }
262    
263                    /* iterate over results */
264                  for (j = 0; j < ncols; j++)                  for (j = 0; j < ncols; j++)
265                  {                  {
266                          values[j] = DatumGetCString( "foo" );                          bool    isnull;
267    
268                            /* array value of this position */
269                            indx[0] = j + attr_dim_lower_bounds[0];
270    
271                            dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
272    
273                            if (!isnull && doc)
274                                    values[j] = DatumGetCString(
275                                            attr2text(doc,
276                                                    (char *)DirectFunctionCall1(textout, dvalue)
277                                            ));
278                            else
279                                    values[j] = NULL;
280                  }                  }
281                  /* construct the tuple */                  /* construct the tuple */
282                  tuple = BuildTupleFromCStrings(attinmeta, values);                  tuple = BuildTupleFromCStrings(attinmeta, values);
283    
284                  /* now store it */                  /* now store it */
285                  tuplestore_puttuple(tupstore, tuple);                  tuplestore_puttuple(tupstore, tuple);
286    
287    
288                    /* delete estraier document object */
289                    est_doc_delete(doc);
290          }          }
291    
292          tuplestore_donestoring(tupstore);          tuplestore_donestoring(tupstore);
# Line 306  Datum pgest2(PG_FUNCTION_ARGS) Line 302  Datum pgest2(PG_FUNCTION_ARGS)
302          rsinfo->setDesc = tupdesc;          rsinfo->setDesc = tupdesc;
303          MemoryContextSwitchTo(oldcontext);          MemoryContextSwitchTo(oldcontext);
304    
305            est_cond_delete(cond);
306    
307            if(!est_db_close(db, &ecode)){
308                    ereport(ERROR, (errcode(ERRCODE_IO_ERROR),
309                            errmsg("est_db_close: %d", ecode),
310                            errdetail(est_err_msg(ecode))));
311            }
312    
313          return (Datum) 0;          return (Datum) 0;
314  }  }
315    
# Line 343  char *attr2text(ESTDOC *doc, char *attr) Line 347  char *attr2text(ESTDOC *doc, char *attr)
347          return val;          return val;
348  }  }
349    
 /* 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;  
 }  
 */  

Legend:
Removed from v.5  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26