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

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

  ViewVC Help
Powered by ViewVC 1.1.26