/[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 19 by dpavlin, Thu May 26 17:56:53 2005 UTC revision 57 by dpavlin, Thu May 11 16:19:38 2006 UTC
# Line 14  Line 14 
14   *   *
15   * Based on:   * Based on:
16   * - C example from PostgreSQL documentation (BSD licence)   * - C example from PostgreSQL documentation (BSD licence)
17   * - example002.c from Hyper Estraier (GPL)   * - coreexample002.c and nodeexample002.c from Hyper Estraier (GPL)
18   * - _textin/_textout from pgcurl.c (LGPL)   * - _textin/_textout from pgcurl.c (LGPL)
19   *   *
20   * This code is licenced under GPL   * This code is licenced under GPL
# Line 25  Line 25 
25  #include "funcapi.h"  #include "funcapi.h"
26  #include "utils/builtins.h"  #include "utils/builtins.h"
27  #include "utils/array.h"  #include "utils/array.h"
28    #include "utils/lsyscache.h"
29  #include "miscadmin.h"  #include "miscadmin.h"
30  #include <estraier.h>  #include <estraier.h>
31  #include <cabin.h>  #include <cabin.h>
32    #include <estnode.h>
33    
34  #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))  #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
35  #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))  #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))
36  #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))  #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
37  #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))  #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
38    
39    /* SortMem got renamed in PostgreSQL 8.0 */
40    #ifndef SortMem
41     #define SortMem 16 * 1024
42    #endif
43    
44    #define ATTR_DELIMITER "{{!}}"
45    #define HINTS_PREFIX "HINTS."
46    
47  /* prototype */  /* prototype */
48  char *attr2text(ESTDOC *doc, char *attr);  char *attr2text(ESTDOC *doc, char *attr);
49    char *node_attr2text(ESTRESDOC *rdoc, char *attr);
50    void cond_add_attr(ESTCOND *cond, char *attr);
51    
52  ESTDB *db;  
53  ESTCOND *cond;  /* work in progress */
54  ESTDOC *doc;  PG_FUNCTION_INFO_V1(pgest_attr);
55  const CBLIST *texts;  Datum pgest_attr(PG_FUNCTION_ARGS)
56  int ecode, *est_result, resnum, i, j;  {
57  int limit = 0;          ArrayType       *attr_arr = PG_GETARG_ARRAYTYPE_P(6);
58  int offset = 0;          Oid             attr_element_type = ARR_ELEMTYPE(attr_arr);
59            int             attr_ndims = ARR_NDIM(attr_arr);
60  /* define PostgreSQL v1 function */          int             *attr_dim_counts = ARR_DIMS(attr_arr);
61  PG_FUNCTION_INFO_V1(pgest);          int             *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
62  Datum pgest(PG_FUNCTION_ARGS) {          int             ncols = 0;
63            int             nrows = 0;
64          FuncCallContext *funcctx;          int             indx[MAXDIM];
65          int             call_cntr;          int16           attr_len;
66          int             max_calls;          bool            attr_byval;
67          TupleDesc       tupdesc;          char            attr_align;
68          TupleTableSlot  *slot;          ReturnSetInfo   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
69          AttInMetadata   *attinmeta;          AttInMetadata   *attinmeta;
70            TupleDesc       tupdesc;
71            Tuplestorestate *tupstore = NULL;
72            HeapTuple       tuple;
73            MemoryContext   per_query_ctx;
74            MemoryContext   oldcontext;
75            Datum           dvalue;
76            char            **values;
77            int             rsinfo_ncols;
78            int             i, j;
79            /* estvars */
80            ESTDB *db;
81            ESTCOND *cond;
82            ESTDOC *doc;
83            int ecode, *est_result, resnum;
84            int limit = 0;
85            int offset = 0;
86    
87          char            *index_path;          char            *index_path;
88          char            *query;          char            *query;
89          char            *attr;          char            *attr;
90            char            *order;
91    
         /* 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));  
92    
93                  /* query string */          /* only allow 1D input array */
94                  if (PG_ARGISNULL(0)) {          if (attr_ndims == 1)
95                          query = "";          {
96                  } else {                  ncols = attr_dim_counts[0];
97                          query = _textout(PG_GETARG_TEXT_P(1));          }
98                  }          else
99                    ereport(ERROR,
100                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
101                                     errmsg("invalid input array"),
102                                     errdetail("Input array must have 1 dimension")));
103                    
104            /* check to see if caller supports us returning a tuplestore */
105            if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
106                    ereport(ERROR,
107                                    (errcode(ERRCODE_SYNTAX_ERROR),
108                                     errmsg("materialize mode required, but it is not " \
109                                                    "allowed in this context")));
110    
111                  /* atribute filter */          /* get info about element type needed to construct the array */
112                  if (PG_ARGISNULL(2)) {          get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
                         attr = "";  
                 } else {  
                         attr = _textout(PG_GETARG_TEXT_P(2));  
                 }  
113    
114                  /* limit */          /* get the requested return tuple description */
115                  if (PG_ARGISNULL(3)) {          tupdesc = rsinfo->expectedDesc;
116                          limit = 0;          rsinfo_ncols = tupdesc->natts;
                 } else {  
                         limit = PG_GETARG_INT32(3);  
                 }  
117    
118                  /* offset */          /*
119                  if (PG_ARGISNULL(4)) {           * The requested tuple description better match up with the array
120                          offset = 0;           * we were given.
121                  } else {           */
122                          offset = PG_GETARG_INT32(4);          if (rsinfo_ncols != ncols)
123                  }                  ereport(ERROR,
124                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
125                                     errmsg("invalid input array"),
126                                     errdetail("Number of elements in array must match number of query specified columns.")));
127    
128            /* OK, use it */
129            attinmeta = TupleDescGetAttInMetadata(tupdesc);
130    
131                  /* open the database */          /* Now go to work */
132                  elog(DEBUG1, "pgest: est_db_open(%s)", index_path);          rsinfo->returnMode = SFRM_Materialize;
                   
                 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(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())) {  
                         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(INFO,"est_cond_add_attr(%s)", attr);  
                         est_cond_add_attr(cond, attr);  
                 }  
133    
134                  /* get the result of search */          per_query_ctx = fcinfo->flinfo->fn_mcxt;
135                  est_result = est_db_search(db, cond, &resnum, NULL);          oldcontext = MemoryContextSwitchTo(per_query_ctx);
136                    
137                  /* total number of tuples to be returned */          /* initialize our tuplestore */
138                  if (limit && limit < resnum) {          tupstore = tuplestore_begin_heap(true, false, SortMem);
139                          funcctx->max_calls = limit - offset;  
140                  } else {  
141                          funcctx->max_calls = resnum - offset;          /* take rest of arguments from function */
                 }  
142    
143                  /* check if results exists */          /* index path */
144                  if ( 0 == funcctx->max_calls )          if (PG_ARGISNULL(0)) {
145                          elog(INFO, "pgest: no results for: %s", query );                  ereport(ERROR,
146                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
147                                     errmsg("index path can't be null"),
148                                     errdetail("Index path must be valid full path to HyperEstraier index")));
149            }
150            index_path = _textout(PG_GETARG_TEXT_P(0));
151    
152                  elog(DEBUG1, "pgest: found %d hits for %s", resnum, query);          /* query string */
153            if (PG_ARGISNULL(1)) {
154                    query = "";
155            } else {
156                    query = _textout(PG_GETARG_TEXT_P(1));
157            }
158    
159                  /* Build a tuple description for a __pgest tuple */          /* atribute filter */
160                  tupdesc = RelationNameGetTupleDesc("__pgest");          if (PG_ARGISNULL(2)) {
161                    attr = "";
162            } else {
163                    attr = _textout(PG_GETARG_TEXT_P(2));
164            }
165            
166            /* sort order */
167            if (PG_ARGISNULL(3)) {
168                    order = "";
169            } else {
170                    order = _textout(PG_GETARG_TEXT_P(3));
171            }
172    
173    
174            /* limit */
175            if (PG_ARGISNULL(4)) {
176                    limit = 0;
177            } else {
178                    limit = PG_GETARG_INT32(4);
179            }
180    
181            /* offset */
182            if (PG_ARGISNULL(5)) {
183                    offset = 0;
184            } else {
185                    offset = PG_GETARG_INT32(5);
186            }
187    
                 /* allocate a slot for a tuple with this tupdesc */  
                 slot = TupleDescGetSlot(tupdesc);  
188    
189                  /* assign slot to function context */          /* open the database */
190                  funcctx->slot = slot;          elog(DEBUG1, "pgest_attr: est_db_open(%s)", index_path);
191                    
192            if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){
193                    ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
194                            errmsg("est_db_open: can't open %s: %d", index_path, ecode),
195                            errdetail(est_err_msg(ecode))));
196            }
197                    
198            elog(DEBUG1, "pgest_attr: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset);
199            
200            /* create a search condition object */
201            if (!(cond = est_cond_new())) {
202                    ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
203                            errmsg("pgest_attr: est_cond_new failed")));
204            }
205            
206            /* set the search phrase to the search condition object */
207            if (! PG_ARGISNULL(1) && strlen(query) > 0)
208                    est_cond_set_phrase(cond, query);
209    
210                  /*          /* minimum valid attribute length is 10: @a STREQ a */
211                   * generate attribute metadata needed later to produce tuples from raw          if (! PG_ARGISNULL(2) && strlen(attr) >= 10) {
212                   * C strings                  elog(DEBUG1,"attributes: %s", attr);
213                   */                  cond_add_attr(cond, attr);
214                  attinmeta = TupleDescGetAttInMetadata(tupdesc);          }
                 funcctx->attinmeta = attinmeta;  
215    
216                  MemoryContextSwitchTo(oldcontext);          /* set the search phrase to the search condition object */
217            if (! PG_ARGISNULL(3) && strlen(order) > 0) {
218                    elog(DEBUG1,"est_cond_set_order(%s)", order);
219                    est_cond_set_order(cond, order);
220            }
221    
222                  elog(DEBUG1, "SRF_IS_FIRSTCALL done");          if (limit) {
223                    elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
224                    est_cond_set_max(cond, limit + offset);
225          }          }
226    
227          /* stuff done on every call of the function */          /* get the result of search */
228          funcctx = SRF_PERCALL_SETUP();          est_result = est_db_search(db, cond, &resnum, NULL);
229    
230          call_cntr = funcctx->call_cntr;          /* check if results exists */
231          max_calls = funcctx->max_calls;          if ( 0 == resnum ) {
232          slot = funcctx->slot;                  elog(INFO, "pgest_attr: no results for: %s", query );
233          attinmeta = funcctx->attinmeta;          }
234    
235          if (limit && call_cntr > limit - 1) {          /* total number of tuples to be returned */
236                  elog(INFO, "call_cntr: %d limit: %d", call_cntr, limit);          if (limit && limit < resnum) {
237                  SRF_RETURN_DONE(funcctx);                  nrows = limit;
238            } else {
239                    nrows = resnum - offset;
240          }          }
241    
         if (call_cntr < max_calls) {  
                 char            **values;  
                 HeapTuple       tuple;  
                 Datum           result;  
242    
243                  elog(DEBUG1, "pgest: loop count %d", call_cntr);          elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);
244    
245                  if (! est_result) {          values = (char **) palloc(ncols * sizeof(char *));
                         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.  
                  */  
246    
247                  if (doc = est_db_get_doc(db, est_result[call_cntr + offset], 0)) {          for (i = 0; i < nrows; i++)
248                            {
249    
250                    /* get result from estraier */
251                    if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {
252                            elog(INFO, "pgest_attr: can't find result %d", i + offset);
253                    } else {
254                          elog(DEBUG1, "URI: %s\n Title: %s\n",                          elog(DEBUG1, "URI: %s\n Title: %s\n",
255                                  est_doc_attr(doc, "@uri"),                                  est_doc_attr(doc, "@uri"),
256                                  est_doc_attr(doc, "@title")                                  est_doc_attr(doc, "@title")
257                          );                          );
258                    }
259    
260                    /* iterate over results */
261                    for (j = 0; j < ncols; j++)
262                    {
263                            bool    isnull;
264    
265                          values = (char **) palloc(4 * sizeof(char *));                          /* array value of this position */
266                            indx[0] = j + attr_dim_lower_bounds[0];
267    
268  //                      values[0] = (char *) palloc(strlen(_estval) * sizeof(char));                          dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
269    
270                          values[0] = (char *) attr2text(doc,"@id");                          if (!isnull && doc)
271                          values[1] = (char *) attr2text(doc,"@uri");                                  values[j] = DatumGetCString(
272                          values[2] = (char *) attr2text(doc,"@title");                                          attr2text(doc,
273                          values[3] = (char *) attr2text(doc,"@size");                                                  (char *)DirectFunctionCall1(textout, dvalue)
274                                            ));
275                          /* destloy the document object */                          else
276                          elog(DEBUG2, "est_doc_delete");                                  values[j] = NULL;
                         est_doc_delete(doc);  
                 } else {  
                         elog(INFO, "no result from estraier");  
                         values[0] = DatumGetCString( "" );  
                         values[1] = DatumGetCString( "" );  
                         values[2] = DatumGetCString( "" );  
                         values[3] = DatumGetCString( "" );  
277                  }                  }
278                    /* construct the tuple */
279                    tuple = BuildTupleFromCStrings(attinmeta, values);
280    
281                    /* now store it */
282                    tuplestore_puttuple(tupstore, tuple);
283    
284                  elog(DEBUG2, "build tuple");                  /* delete estraier document object */
285                  /* build a tuple */                  if (doc) est_doc_delete(doc);
286                  tuple = BuildTupleFromCStrings(attinmeta, values);          }
287    
288                  elog(DEBUG2, "make tuple into datum");          tuplestore_donestoring(tupstore);
289                  /* make the tuple into a datum */          rsinfo->setResult = tupstore;
                 result = TupleGetDatum(slot, tuple);  
290    
291                  elog(DEBUG2, "cleanup");          /*
292                  /* clean up ? */           * SFRM_Materialize mode expects us to return a NULL Datum. The actual
293  /*           * tuples are in our tuplestore and passed back through
294                  pfree(values[0]);           * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
295                  pfree(values[1]);           * that we actually used to build our tuples with, so the caller can
296                  pfree(values[2]);           * verify we did what it was expecting.
297                  pfree(values[3]);           */
298                  pfree(values);          rsinfo->setDesc = tupdesc;
299  */          MemoryContextSwitchTo(oldcontext);
                   
                 elog(DEBUG2, "cleanup over");  
           
                 SRF_RETURN_NEXT(funcctx, result);  
         } else {  
                 elog(DEBUG1, "loop over");  
300    
301                  if(!est_db_close(db, &ecode)){          est_cond_delete(cond);
302                          elog(INFO, "est_db_close error: %s", est_err_msg(ecode));  
303                  }          if(!est_db_close(db, &ecode)){
304                    ereport(ERROR, (errcode(ERRCODE_IO_ERROR),
305                            errmsg("est_db_close: %d", ecode),
306                            errdetail(est_err_msg(ecode))));
307            }
308    
309                  /* do when there is no more left */          return (Datum) 0;
310                  SRF_RETURN_DONE(funcctx);  }
311    
312    
313    /* make text var from attr */
314    char *attr2text(ESTDOC *doc, char *attr) {
315            char *val;
316            const char *attrval;
317            int len;
318            int attrlen;
319    
320            if (! doc) return (Datum) NULL;
321    
322            elog(DEBUG1, "doc: %p, attr: %s", doc, attr);
323    
324            if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {
325                    val = (char *) palloc(attrlen * sizeof(char));
326            } else {
327                    return (Datum) NULL;
328          }          }
329    
330            len = strlen(attrval);
331            elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);
332    
333            len++;
334            len *= sizeof(char);
335    
336            elog(DEBUG2, "palloc(%d)", len);
337    
338            val = palloc(len);
339    
340            memset(val, 0, len);
341            strncpy(val, attrval, len);
342    
343            elog(DEBUG2, "val=%s", val);
344    
345            return val;
346  }  }
347    
348  /* work in progress */  /*
349  PG_FUNCTION_INFO_V1(pgest_attr);   * variation on theme: use node API which doesn't open index on
350  Datum pgest_attr(PG_FUNCTION_ARGS)   * every query which is much faster for large indexes
351     *
352     */
353    
354    /* select * from pgest( */
355    #define _arg_node_uri 0
356    #define _arg_login 1
357    #define _arg_passwd 2
358    #define _arg_depth 3
359    #define _arg_query 4
360    #define _arg_attr 5
361    #define _arg_order 6
362    #define _arg_limit 7
363    #define _arg_offset 8
364    #define _arg_attr_array 9
365    /* as (foo text, ... ); */
366    
367    
368    PG_FUNCTION_INFO_V1(pgest_node);
369    Datum pgest_node(PG_FUNCTION_ARGS)
370  {  {
371          ArrayType       *attr_arr = PG_GETARG_ARRAYTYPE_P(5);          ArrayType       *attr_arr = PG_GETARG_ARRAYTYPE_P(_arg_attr_array);
372          Oid             element_type = ARR_ELEMTYPE(attr_arr);          Oid             attr_element_type = ARR_ELEMTYPE(attr_arr);
373          int             ndims = ARR_NDIM(attr_arr);          int             attr_ndims = ARR_NDIM(attr_arr);
374          int             *dim_counts = ARR_DIMS(attr_arr);          int             *attr_dim_counts = ARR_DIMS(attr_arr);
375          int             *dim_lower_bounds = ARR_LBOUND(attr_arr);          int             *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
376          int             ncols = 0;          int             ncols = 0;
377          int             nrows = 0;          int             nrows = 0;
378          int             indx[MAXDIM];          int             indx[MAXDIM];
379          int16           typlen;          int16           attr_len;
380          bool            typbyval;          bool            attr_byval;
381          char            typalign;          char            attr_align;
382          ReturnSetInfo   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;          ReturnSetInfo   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
383          AttInMetadata   *attinmeta;          AttInMetadata   *attinmeta;
384          TupleDesc       tupdesc;          TupleDesc       tupdesc;
# Line 288  Datum pgest_attr(PG_FUNCTION_ARGS) Line 391  Datum pgest_attr(PG_FUNCTION_ARGS)
391          int             rsinfo_ncols;          int             rsinfo_ncols;
392          int             i, j;          int             i, j;
393          /* estvars */          /* estvars */
394          char            *index_path;          ESTNODE *node;
395            ESTCOND *cond;
396            ESTNODERES *nres;
397            ESTRESDOC *rdoc;
398            CBMAP *hints;
399            int resnum = 0;
400            int limit = 0;
401            int offset = 0;
402            int depth = 0;
403    
404            char            *node_url;
405            char            *user, *passwd;
406          char            *query;          char            *query;
407          char            *attr;          char            *attr;
408            char            *order;
409    
410    
411          /* only allow 1D input array */          /* only allow 1D input array */
412          if (ndims == 1)          if (attr_ndims == 1)
413          {          {
414                  ncols = dim_counts[0];                  ncols = attr_dim_counts[0];
415          }          }
416          else          else
417                  ereport(ERROR,                  ereport(ERROR,
# Line 312  Datum pgest_attr(PG_FUNCTION_ARGS) Line 427  Datum pgest_attr(PG_FUNCTION_ARGS)
427                                                  "allowed in this context")));                                                  "allowed in this context")));
428    
429          /* get info about element type needed to construct the array */          /* get info about element type needed to construct the array */
430          get_typlenbyvalalign(element_type, &typlen, &typbyval, &typalign);          get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
431    
432          /* get the requested return tuple description */          /* get the requested return tuple description */
433          tupdesc = rsinfo->expectedDesc;          tupdesc = rsinfo->expectedDesc;
# Line 343  Datum pgest_attr(PG_FUNCTION_ARGS) Line 458  Datum pgest_attr(PG_FUNCTION_ARGS)
458    
459          /* take rest of arguments from function */          /* take rest of arguments from function */
460    
461          /* index path */          /* node URL */
462          if (PG_ARGISNULL(0)) {          if (PG_ARGISNULL(_arg_node_uri)) {
463                  ereport(ERROR,                  ereport(ERROR,
464                                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),                                  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
465                                   errmsg("index path can't be null"),                                   errmsg("node URL can't be null"),
466                                   errdetail("Index path must be valid full path to HyperEstraier index")));                                   errdetail("Node URL must be valid URL to HyperEstraier node")));
467            }
468            node_url = _textout(PG_GETARG_TEXT_P(_arg_node_uri));
469    
470            /* login and password */
471            if (PG_ARGISNULL(_arg_login) || PG_ARGISNULL(_arg_passwd)) {
472                    ereport(ERROR,
473                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
474                                     errmsg("username and password can't be NULL"),
475                                     errdetail("You must specify valid username and password to HyperEstraier node")));
476            }
477            user = _textout(PG_GETARG_TEXT_P(_arg_login));
478            passwd = _textout(PG_GETARG_TEXT_P(_arg_passwd));
479    
480            /* depth of search */
481            if (PG_ARGISNULL(_arg_depth)) {
482                    depth = 0;
483            } else {
484                    depth = PG_GETARG_INT32(_arg_depth);
485          }          }
         index_path = _textout(PG_GETARG_TEXT_P(0));  
486    
487          /* query string */          /* query string */
488          if (PG_ARGISNULL(0)) {          if (PG_ARGISNULL(_arg_query)) {
489                  query = "";                  query = "";
490          } else {          } else {
491                  query = _textout(PG_GETARG_TEXT_P(1));                  query = _textout(PG_GETARG_TEXT_P(_arg_query));
492          }          }
493    
494          /* atribute filter */          /* atribute filter */
495          if (PG_ARGISNULL(2)) {          if (PG_ARGISNULL(_arg_attr)) {
496                  attr = "";                  attr = "";
497          } else {          } else {
498                  attr = _textout(PG_GETARG_TEXT_P(2));                  attr = _textout(PG_GETARG_TEXT_P(_arg_attr));
499          }          }
500            
501            /* sort order */
502            if (PG_ARGISNULL(_arg_order)) {
503                    order = "";
504            } else {
505                    order = _textout(PG_GETARG_TEXT_P(_arg_order));
506            }
507    
508    
509          /* limit */          /* limit */
510          if (PG_ARGISNULL(3)) {          if (PG_ARGISNULL(_arg_limit)) {
511                  limit = 0;                  limit = 0;
512          } else {          } else {
513                  limit = PG_GETARG_INT32(3);                  limit = PG_GETARG_INT32(_arg_limit);
514          }          }
515    
516          /* offset */          /* offset */
517          if (PG_ARGISNULL(4)) {          if (PG_ARGISNULL(_arg_offset)) {
518                  offset = 0;                  offset = 0;
519          } else {          } else {
520                  offset = PG_GETARG_INT32(4);                  offset = PG_GETARG_INT32(_arg_offset);
521          }          }
522    
523            /* initialize the network environment */
524          /* open the database */          if(!est_init_net_env()){
525          elog(DEBUG1, "pgest_attr: est_db_open(%s)", index_path);                  ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
526                                            errmsg("pgest_node: can't create network enviroment")));
         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))));  
527          }          }
528                    
529          elog(INFO, "pgest_attr: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset);          /* create the node connection object */
530            elog(DEBUG1, "pgest_node: est_node_new(%s) as %s", node_url, user);
531            node = est_node_new(node_url);
532            est_node_set_auth(node, user, passwd);
533    
534            elog(DEBUG1, "pgest_node: node: %s (d:%d) query[%s] attr[%s] limit %d offset %d", node_url, depth, query, (PG_ARGISNULL(_arg_attr) ? "NULL" : attr), limit, offset);
535                    
536          /* create a search condition object */          /* create a search condition object */
537          if (!(cond = est_cond_new())) {          if (!(cond = est_cond_new())) {
538                  ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),                  ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
539                          errmsg("pgest_attr: est_cond_new failed")));                          errmsg("pgest_node: est_cond_new failed")));
540          }          }
541                    
542          /* set the search phrase to the search condition object */          /* set the search phrase to the search condition object */
543          if (! PG_ARGISNULL(1) && strlen(query) > 0)          if (! PG_ARGISNULL(_arg_query) && strlen(query) > 0)
544                  est_cond_set_phrase(cond, query);                  est_cond_set_phrase(cond, query);
545    
546          /* minimum valid attribute length is 10: @a STREQ a */          /* minimum valid attribute length is 10: @a STREQ a */
547          if (! PG_ARGISNULL(2) && strlen(attr) >= 10) {          if (! PG_ARGISNULL(_arg_attr) && strlen(attr) >= 10) {
548                  elog(INFO,"est_cond_add_attr(%s)", attr);                  elog(DEBUG1,"attributes: %s", attr);
549                  est_cond_add_attr(cond, attr);                  cond_add_attr(cond, attr);
550            }
551    
552            /* set the search phrase to the search condition object */
553            if (! PG_ARGISNULL(_arg_order) && strlen(order) > 0) {
554                    elog(DEBUG1,"est_cond_set_order(%s)", order);
555                    est_cond_set_order(cond, order);
556            }
557    
558            if (limit) {
559                    elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
560                    est_cond_set_max(cond, limit + offset);
561            }
562    
563            if (offset) {
564                    elog(DEBUG1,"est_cond_set_skip(%d)", offset);
565                    est_cond_set_skip(cond, offset);
566          }          }
567    
568          /* get the result of search */          /* get the result of search */
569          est_result = est_db_search(db, cond, &resnum, NULL);          nres = est_node_search(node, cond, depth);
570    
571            if (! nres) {
572                    int status = est_node_status(node);
573                    est_cond_delete(cond);
574                    est_node_delete(node);
575                    est_free_net_env();
576                    ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
577                            errmsg("pgest_node: search failed, node status %d", status)));
578            }
579    
580            /* get number of results */
581            resnum = est_noderes_doc_num(nres);
582    
583          /* check if results exists */          /* check if results exists */
584          if ( 0 == resnum ) {          if ( 0 == resnum ) {
585                  elog(INFO, "pgest_attr: no results for: %s", query );                  elog(INFO, "pgest_node: no results for: %s", query );
586          }          }
587    
588          /* total number of tuples to be returned */          /* total number of tuples to be returned */
589          if (limit && limit < resnum) {          if (limit && limit < resnum) {
590                  nrows = limit - offset;                  nrows = limit;
591          } else {          } else {
592                  nrows = resnum - offset;                  nrows = resnum - offset;
593          }          }
594    
595            /* get hints */
596            hints = est_noderes_hints(nres);
597    
598          elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);          elog(DEBUG1, "pgest_node: found %d hits for %s", resnum, query);
599    
600    
601          values = (char **) palloc(ncols * sizeof(char *));          values = (char **) palloc(ncols * sizeof(char *));
# Line 433  Datum pgest_attr(PG_FUNCTION_ARGS) Line 604  Datum pgest_attr(PG_FUNCTION_ARGS)
604          {          {
605    
606                  /* get result from estraier */                  /* get result from estraier */
607                  if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {                  if (! ( rdoc = est_noderes_get_doc(nres, i) )) {
608                          elog(INFO, "can't find result %d", i + offset);                          elog(INFO, "pgest_node: can't find result %d", i + offset);
609                  } else {                  } else {
610                          elog(DEBUG1, "URI: %s\n Title: %s\n",                          elog(DEBUG1, "URI: %s\n Title: %s\n",
611                                  est_doc_attr(doc, "@uri"),                                  est_resdoc_attr(rdoc, "@uri"),
612                                  est_doc_attr(doc, "@title")                                  est_resdoc_attr(rdoc, "@title")
613                          );                          );
614                  }                  }
615    
# Line 446  Datum pgest_attr(PG_FUNCTION_ARGS) Line 617  Datum pgest_attr(PG_FUNCTION_ARGS)
617                  for (j = 0; j < ncols; j++)                  for (j = 0; j < ncols; j++)
618                  {                  {
619                          bool    isnull;                          bool    isnull;
620                            char    *attr;  /* current attribute name */
621                            char    *hint;  /* position of current hint in attribute */
622                            char    *hint_val;
623    
624                          /* array value of this position */                          /* array value of this position */
625                          indx[0] = j + dim_lower_bounds[0];                          indx[0] = j + attr_dim_lower_bounds[0];
626    
627                          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);
628                            attr = (char *)DirectFunctionCall1(textout, dvalue);
629    
630                          if (!isnull && doc)                          if (!isnull && (hint = strstr(attr, HINTS_PREFIX)) != NULL) {
631                                  values[j] = DatumGetCString(                                  /* skip HINTS. prefix */
632                                          attr2text(doc,                                  hint += strlen(HINTS_PREFIX);
633                                                  DirectFunctionCall1(textout, dvalue)  
634                                          ));                                  hint_val = cbmapget(hints, hint, -1, NULL);
635                                    elog(DEBUG2, "hint %s = %s", hint, hint_val);
636    
637                                    if (hint_val != NULL) {
638                                            values[j] = DatumGetCString( hint_val );
639                                    } else {
640                                            elog(INFO, "can't get hint in results: %s", hint);
641                                            values[j] = NULL;
642                                    }
643                            } else if (!isnull && rdoc)
644                                    values[j] = DatumGetCString( node_attr2text(rdoc, attr) );
645                          else                          else
646                                  values[j] = NULL;                                  values[j] = NULL;
647                  }                  }
# Line 466  Datum pgest_attr(PG_FUNCTION_ARGS) Line 651  Datum pgest_attr(PG_FUNCTION_ARGS)
651                  /* now store it */                  /* now store it */
652                  tuplestore_puttuple(tupstore, tuple);                  tuplestore_puttuple(tupstore, tuple);
653    
   
                 /* delete estraier document object */  
                 est_doc_delete(doc);  
654          }          }
655    
656          tuplestore_donestoring(tupstore);          tuplestore_donestoring(tupstore);
# Line 484  Datum pgest_attr(PG_FUNCTION_ARGS) Line 666  Datum pgest_attr(PG_FUNCTION_ARGS)
666          rsinfo->setDesc = tupdesc;          rsinfo->setDesc = tupdesc;
667          MemoryContextSwitchTo(oldcontext);          MemoryContextSwitchTo(oldcontext);
668    
669          if(!est_db_close(db, &ecode)){          /* delete the node result object */
670                  ereport(ERROR, (errcode(ERRCODE_IO_ERROR),          est_noderes_delete(nres);
671                          errmsg("est_db_close: %d", ecode),  
672                          errdetail(est_err_msg(ecode))));          /* destroy the search condition object */                          
673          }          est_cond_delete(cond);
674    
675            /* destroy the node object */
676            est_node_delete(node);
677    
678            /* free the networking environment */
679            est_free_net_env();
680    
681          return (Datum) 0;          return (Datum) 0;
682  }  }
683    
684    /* make text var from node attr */
685  /* make text var from attr */  char *node_attr2text(ESTRESDOC *rdoc, char *attr) {
 char *attr2text(ESTDOC *doc, char *attr) {  
686          char *val;          char *val;
687          const char *attrval;          const char *attrval;
688          int len;          int len;
689          int attrlen;          int attrlen;
690    
691          elog(DEBUG1, "doc: %08x, attr: %s", doc, attr);          if (! rdoc) return (Datum) NULL;
692    
693          if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {          elog(DEBUG1, "doc: %p, attr: %s", rdoc, attr);
694    
695            if ( (attrval = est_resdoc_attr(rdoc, attr)) && (attrlen = strlen(attrval)) ) {
696                  val = (char *) palloc(attrlen * sizeof(char));                  val = (char *) palloc(attrlen * sizeof(char));
697          } else {          } else {
698                  return (Datum) NULL;                  return (Datum) NULL;
699          }          }
700    
701          len = strlen(attrval);          len = strlen(attrval);
702          elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);          elog(DEBUG1, "node_attr2text(%s) = '%s' %d bytes", attr, attrval, len);
703    
704          len++;          len++;
705          len *= sizeof(char);          len *= sizeof(char);
# Line 527  char *attr2text(ESTDOC *doc, char *attr) Line 716  char *attr2text(ESTDOC *doc, char *attr)
716          return val;          return val;
717  }  }
718    
719    /* parse attributes and add them to confition */
720    void cond_add_attr(ESTCOND *cond, char *attr) {
721            char *next;
722            char *curr_attr;
723            while ( strlen(attr) > 0 ) {
724                    printf("len [%s] = %d\n", attr, strlen(attr));
725                    if ((next = strstr(attr, ATTR_DELIMITER)) != NULL) {
726                            curr_attr = palloc( next - attr + 1 );
727                            memcpy(curr_attr, attr, next-attr);
728                            curr_attr[next-attr] = '\0';
729                            next += strlen(ATTR_DELIMITER);
730                    } else {
731                            next = "";
732                            curr_attr = attr;
733                    }
734                    elog(DEBUG1, "est_cond_add_attr(%s)", curr_attr);
735                    est_cond_add_attr(cond, curr_attr);
736                    attr = next;
737            }
738    }

Legend:
Removed from v.19  
changed lines
  Added in v.57

  ViewVC Help
Powered by ViewVC 1.1.26