/[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

Annotation of /trunk/pgest.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 57 - (hide annotations)
Thu May 11 16:19:38 2006 UTC (17 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 18675 byte(s)
initial implementation of hints using (fake) atribute names in form HINTS.something
(e.g. HITS.HIT or HINTS.WORDNUM...)
1 dpavlin 1 /*
2     * integrate Hyper Estraier into PostgreSQL
3     *
4     * Dobrica Pavlinusic <dpavlin@rot13.org> 2005-05-19
5     *
6     * TODO:
7     * - all
8     *
9     * NOTES:
10     * - clear structures with memset to support hash indexes (who whould like
11     * to create hash index on table returned from function?)
12     * - number of returned rows is set by PostgreSQL evaluator, see:
13     * http://archives.postgresql.org/pgsql-hackers/2005-02/msg00546.php
14     *
15     * Based on:
16     * - C example from PostgreSQL documentation (BSD licence)
17 dpavlin 41 * - coreexample002.c and nodeexample002.c from Hyper Estraier (GPL)
18 dpavlin 1 * - _textin/_textout from pgcurl.c (LGPL)
19     *
20     * This code is licenced under GPL
21     */
22    
23     #include "postgres.h"
24     #include "fmgr.h"
25     #include "funcapi.h"
26     #include "utils/builtins.h"
27     #include "utils/array.h"
28 dpavlin 56 #include "utils/lsyscache.h"
29 dpavlin 1 #include "miscadmin.h"
30     #include <estraier.h>
31     #include <cabin.h>
32 dpavlin 41 #include <estnode.h>
33 dpavlin 1
34     #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
35     #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))
36     #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
37     #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
38    
39 dpavlin 27 /* SortMem got renamed in PostgreSQL 8.0 */
40     #ifndef SortMem
41     #define SortMem 16 * 1024
42     #endif
43    
44 dpavlin 40 #define ATTR_DELIMITER "{{!}}"
45 dpavlin 57 #define HINTS_PREFIX "HINTS."
46 dpavlin 40
47 dpavlin 5 /* prototype */
48     char *attr2text(ESTDOC *doc, char *attr);
49 dpavlin 41 char *node_attr2text(ESTRESDOC *rdoc, char *attr);
50 dpavlin 56 void cond_add_attr(ESTCOND *cond, char *attr);
51 dpavlin 1
52    
53     /* work in progress */
54 dpavlin 19 PG_FUNCTION_INFO_V1(pgest_attr);
55     Datum pgest_attr(PG_FUNCTION_ARGS)
56 dpavlin 1 {
57 dpavlin 31 ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(6);
58 dpavlin 25 Oid attr_element_type = ARR_ELEMTYPE(attr_arr);
59     int attr_ndims = ARR_NDIM(attr_arr);
60     int *attr_dim_counts = ARR_DIMS(attr_arr);
61     int *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
62 dpavlin 19 int ncols = 0;
63     int nrows = 0;
64     int indx[MAXDIM];
65 dpavlin 25 int16 attr_len;
66     bool attr_byval;
67     char attr_align;
68 dpavlin 1 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
69     AttInMetadata *attinmeta;
70     TupleDesc tupdesc;
71 dpavlin 19 Tuplestorestate *tupstore = NULL;
72 dpavlin 1 HeapTuple tuple;
73     MemoryContext per_query_ctx;
74     MemoryContext oldcontext;
75     Datum dvalue;
76     char **values;
77 dpavlin 19 int rsinfo_ncols;
78 dpavlin 1 int i, j;
79 dpavlin 19 /* estvars */
80 dpavlin 25 ESTDB *db;
81     ESTCOND *cond;
82     ESTDOC *doc;
83     int ecode, *est_result, resnum;
84     int limit = 0;
85     int offset = 0;
86    
87 dpavlin 19 char *index_path;
88     char *query;
89     char *attr;
90 dpavlin 31 char *order;
91 dpavlin 1
92 dpavlin 19
93     /* only allow 1D input array */
94 dpavlin 25 if (attr_ndims == 1)
95 dpavlin 19 {
96 dpavlin 25 ncols = attr_dim_counts[0];
97 dpavlin 19 }
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 dpavlin 1 /* 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 dpavlin 19 /* get info about element type needed to construct the array */
112 dpavlin 25 get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
113 dpavlin 19
114 dpavlin 1 /* get the requested return tuple description */
115     tupdesc = rsinfo->expectedDesc;
116 dpavlin 19 rsinfo_ncols = tupdesc->natts;
117 dpavlin 1
118     /*
119     * The requested tuple description better match up with the array
120     * we were given.
121     */
122 dpavlin 19 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 dpavlin 1 /* OK, use it */
129     attinmeta = TupleDescGetAttInMetadata(tupdesc);
130    
131     /* Now go to work */
132     rsinfo->returnMode = SFRM_Materialize;
133    
134     per_query_ctx = fcinfo->flinfo->fn_mcxt;
135     oldcontext = MemoryContextSwitchTo(per_query_ctx);
136    
137     /* initialize our tuplestore */
138     tupstore = tuplestore_begin_heap(true, false, SortMem);
139    
140 dpavlin 19
141     /* take rest of arguments from function */
142    
143     /* index path */
144     if (PG_ARGISNULL(0)) {
145     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     /* query string */
153 dpavlin 31 if (PG_ARGISNULL(1)) {
154 dpavlin 19 query = "";
155     } else {
156     query = _textout(PG_GETARG_TEXT_P(1));
157     }
158    
159     /* atribute filter */
160     if (PG_ARGISNULL(2)) {
161     attr = "";
162     } else {
163     attr = _textout(PG_GETARG_TEXT_P(2));
164     }
165 dpavlin 31
166     /* sort order */
167     if (PG_ARGISNULL(3)) {
168     order = "";
169     } else {
170     order = _textout(PG_GETARG_TEXT_P(3));
171     }
172 dpavlin 19
173 dpavlin 31
174 dpavlin 19 /* limit */
175 dpavlin 31 if (PG_ARGISNULL(4)) {
176 dpavlin 19 limit = 0;
177     } else {
178 dpavlin 31 limit = PG_GETARG_INT32(4);
179 dpavlin 19 }
180    
181     /* offset */
182 dpavlin 31 if (PG_ARGISNULL(5)) {
183 dpavlin 19 offset = 0;
184     } else {
185 dpavlin 31 offset = PG_GETARG_INT32(5);
186 dpavlin 19 }
187    
188    
189     /* open the database */
190     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 dpavlin 20 elog(DEBUG1, "pgest_attr: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset);
199 dpavlin 19
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     if (! PG_ARGISNULL(2) && strlen(attr) >= 10) {
212 dpavlin 40 elog(DEBUG1,"attributes: %s", attr);
213 dpavlin 56 cond_add_attr(cond, attr);
214 dpavlin 19 }
215    
216 dpavlin 31 /* 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 dpavlin 38 if (limit) {
223     elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
224     est_cond_set_max(cond, limit + offset);
225     }
226    
227 dpavlin 19 /* get the result of search */
228     est_result = est_db_search(db, cond, &resnum, NULL);
229    
230     /* check if results exists */
231     if ( 0 == resnum ) {
232     elog(INFO, "pgest_attr: no results for: %s", query );
233     }
234    
235     /* total number of tuples to be returned */
236     if (limit && limit < resnum) {
237 dpavlin 31 nrows = limit;
238 dpavlin 19 } else {
239     nrows = resnum - offset;
240     }
241    
242    
243     elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);
244    
245 dpavlin 1 values = (char **) palloc(ncols * sizeof(char *));
246    
247     for (i = 0; i < nrows; i++)
248     {
249 dpavlin 19
250     /* get result from estraier */
251     if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {
252 dpavlin 47 elog(INFO, "pgest_attr: can't find result %d", i + offset);
253 dpavlin 19 } else {
254     elog(DEBUG1, "URI: %s\n Title: %s\n",
255     est_doc_attr(doc, "@uri"),
256     est_doc_attr(doc, "@title")
257     );
258     }
259    
260     /* iterate over results */
261 dpavlin 1 for (j = 0; j < ncols; j++)
262     {
263 dpavlin 19 bool isnull;
264    
265     /* array value of this position */
266 dpavlin 25 indx[0] = j + attr_dim_lower_bounds[0];
267 dpavlin 19
268 dpavlin 25 dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
269 dpavlin 19
270     if (!isnull && doc)
271     values[j] = DatumGetCString(
272     attr2text(doc,
273 dpavlin 20 (char *)DirectFunctionCall1(textout, dvalue)
274 dpavlin 19 ));
275     else
276     values[j] = NULL;
277 dpavlin 1 }
278     /* construct the tuple */
279     tuple = BuildTupleFromCStrings(attinmeta, values);
280    
281     /* now store it */
282     tuplestore_puttuple(tupstore, tuple);
283 dpavlin 19
284     /* delete estraier document object */
285 dpavlin 47 if (doc) est_doc_delete(doc);
286 dpavlin 1 }
287    
288     tuplestore_donestoring(tupstore);
289     rsinfo->setResult = tupstore;
290    
291     /*
292     * SFRM_Materialize mode expects us to return a NULL Datum. The actual
293     * tuples are in our tuplestore and passed back through
294     * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
295     * that we actually used to build our tuples with, so the caller can
296     * verify we did what it was expecting.
297     */
298     rsinfo->setDesc = tupdesc;
299     MemoryContextSwitchTo(oldcontext);
300    
301 dpavlin 31 est_cond_delete(cond);
302    
303 dpavlin 19 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 dpavlin 1 return (Datum) 0;
310     }
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 dpavlin 4 int attrlen;
319 dpavlin 1
320 dpavlin 47 if (! doc) return (Datum) NULL;
321    
322 dpavlin 56 elog(DEBUG1, "doc: %p, attr: %s", doc, attr);
323 dpavlin 1
324 dpavlin 4 if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {
325     val = (char *) palloc(attrlen * sizeof(char));
326 dpavlin 1 } else {
327     return (Datum) NULL;
328     }
329    
330     len = strlen(attrval);
331 dpavlin 2 elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);
332 dpavlin 1
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 dpavlin 41 /*
349     * variation on theme: use node API which doesn't open index on
350     * every query which is much faster for large indexes
351     *
352     */
353    
354 dpavlin 48 /* select * from pgest( */
355     #define _arg_node_uri 0
356     #define _arg_login 1
357     #define _arg_passwd 2
358 dpavlin 49 #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 dpavlin 48 /* as (foo text, ... ); */
366    
367    
368 dpavlin 41 PG_FUNCTION_INFO_V1(pgest_node);
369     Datum pgest_node(PG_FUNCTION_ARGS)
370     {
371 dpavlin 48 ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(_arg_attr_array);
372 dpavlin 41 Oid attr_element_type = ARR_ELEMTYPE(attr_arr);
373     int attr_ndims = ARR_NDIM(attr_arr);
374     int *attr_dim_counts = ARR_DIMS(attr_arr);
375     int *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
376     int ncols = 0;
377     int nrows = 0;
378     int indx[MAXDIM];
379     int16 attr_len;
380     bool attr_byval;
381     char attr_align;
382     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
383     AttInMetadata *attinmeta;
384     TupleDesc tupdesc;
385     Tuplestorestate *tupstore = NULL;
386     HeapTuple tuple;
387     MemoryContext per_query_ctx;
388     MemoryContext oldcontext;
389     Datum dvalue;
390     char **values;
391     int rsinfo_ncols;
392     int i, j;
393     /* estvars */
394     ESTNODE *node;
395     ESTCOND *cond;
396     ESTNODERES *nres;
397     ESTRESDOC *rdoc;
398 dpavlin 57 CBMAP *hints;
399 dpavlin 41 int resnum = 0;
400     int limit = 0;
401     int offset = 0;
402 dpavlin 49 int depth = 0;
403 dpavlin 41
404     char *node_url;
405     char *user, *passwd;
406     char *query;
407     char *attr;
408     char *order;
409    
410    
411     /* only allow 1D input array */
412     if (attr_ndims == 1)
413     {
414     ncols = attr_dim_counts[0];
415     }
416     else
417     ereport(ERROR,
418     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
419     errmsg("invalid input array"),
420     errdetail("Input array must have 1 dimension")));
421    
422     /* check to see if caller supports us returning a tuplestore */
423     if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
424     ereport(ERROR,
425     (errcode(ERRCODE_SYNTAX_ERROR),
426     errmsg("materialize mode required, but it is not " \
427     "allowed in this context")));
428    
429     /* get info about element type needed to construct the array */
430     get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
431    
432     /* get the requested return tuple description */
433     tupdesc = rsinfo->expectedDesc;
434     rsinfo_ncols = tupdesc->natts;
435    
436     /*
437     * The requested tuple description better match up with the array
438     * we were given.
439     */
440     if (rsinfo_ncols != ncols)
441     ereport(ERROR,
442     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
443     errmsg("invalid input array"),
444     errdetail("Number of elements in array must match number of query specified columns.")));
445    
446     /* OK, use it */
447     attinmeta = TupleDescGetAttInMetadata(tupdesc);
448    
449     /* Now go to work */
450     rsinfo->returnMode = SFRM_Materialize;
451    
452     per_query_ctx = fcinfo->flinfo->fn_mcxt;
453     oldcontext = MemoryContextSwitchTo(per_query_ctx);
454    
455     /* initialize our tuplestore */
456     tupstore = tuplestore_begin_heap(true, false, SortMem);
457    
458    
459     /* take rest of arguments from function */
460    
461     /* node URL */
462 dpavlin 48 if (PG_ARGISNULL(_arg_node_uri)) {
463 dpavlin 41 ereport(ERROR,
464     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
465     errmsg("node URL can't be null"),
466     errdetail("Node URL must be valid URL to HyperEstraier node")));
467     }
468 dpavlin 48 node_url = _textout(PG_GETARG_TEXT_P(_arg_node_uri));
469 dpavlin 41
470     /* login and password */
471 dpavlin 48 if (PG_ARGISNULL(_arg_login) || PG_ARGISNULL(_arg_passwd)) {
472 dpavlin 41 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 dpavlin 48 user = _textout(PG_GETARG_TEXT_P(_arg_login));
478     passwd = _textout(PG_GETARG_TEXT_P(_arg_passwd));
479 dpavlin 41
480 dpavlin 49 /* depth of search */
481     if (PG_ARGISNULL(_arg_depth)) {
482     depth = 0;
483     } else {
484     depth = PG_GETARG_INT32(_arg_depth);
485     }
486    
487 dpavlin 41 /* query string */
488 dpavlin 48 if (PG_ARGISNULL(_arg_query)) {
489 dpavlin 41 query = "";
490     } else {
491 dpavlin 48 query = _textout(PG_GETARG_TEXT_P(_arg_query));
492 dpavlin 41 }
493    
494     /* atribute filter */
495 dpavlin 48 if (PG_ARGISNULL(_arg_attr)) {
496 dpavlin 41 attr = "";
497     } else {
498 dpavlin 48 attr = _textout(PG_GETARG_TEXT_P(_arg_attr));
499 dpavlin 41 }
500    
501     /* sort order */
502 dpavlin 48 if (PG_ARGISNULL(_arg_order)) {
503 dpavlin 41 order = "";
504     } else {
505 dpavlin 48 order = _textout(PG_GETARG_TEXT_P(_arg_order));
506 dpavlin 41 }
507    
508    
509     /* limit */
510 dpavlin 48 if (PG_ARGISNULL(_arg_limit)) {
511 dpavlin 41 limit = 0;
512     } else {
513 dpavlin 48 limit = PG_GETARG_INT32(_arg_limit);
514 dpavlin 41 }
515    
516     /* offset */
517 dpavlin 48 if (PG_ARGISNULL(_arg_offset)) {
518 dpavlin 41 offset = 0;
519     } else {
520 dpavlin 48 offset = PG_GETARG_INT32(_arg_offset);
521 dpavlin 41 }
522    
523     /* initialize the network environment */
524     if(!est_init_net_env()){
525     ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
526     errmsg("pgest_node: can't create network enviroment")));
527     }
528    
529     /* 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 dpavlin 49 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 dpavlin 41
536     /* create a search condition object */
537     if (!(cond = est_cond_new())) {
538     ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
539     errmsg("pgest_node: est_cond_new failed")));
540     }
541    
542     /* set the search phrase to the search condition object */
543 dpavlin 48 if (! PG_ARGISNULL(_arg_query) && strlen(query) > 0)
544 dpavlin 41 est_cond_set_phrase(cond, query);
545    
546     /* minimum valid attribute length is 10: @a STREQ a */
547 dpavlin 48 if (! PG_ARGISNULL(_arg_attr) && strlen(attr) >= 10) {
548 dpavlin 41 elog(DEBUG1,"attributes: %s", attr);
549 dpavlin 56 cond_add_attr(cond, attr);
550 dpavlin 41 }
551    
552     /* set the search phrase to the search condition object */
553 dpavlin 48 if (! PG_ARGISNULL(_arg_order) && strlen(order) > 0) {
554 dpavlin 41 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 dpavlin 51 if (offset) {
564     elog(DEBUG1,"est_cond_set_skip(%d)", offset);
565     est_cond_set_skip(cond, offset);
566     }
567    
568 dpavlin 41 /* get the result of search */
569 dpavlin 49 nres = est_node_search(node, cond, depth);
570 dpavlin 41
571 dpavlin 44 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 dpavlin 41 /* get number of results */
581     resnum = est_noderes_doc_num(nres);
582    
583     /* check if results exists */
584     if ( 0 == resnum ) {
585     elog(INFO, "pgest_node: no results for: %s", query );
586     }
587    
588     /* total number of tuples to be returned */
589     if (limit && limit < resnum) {
590     nrows = limit;
591     } else {
592     nrows = resnum - offset;
593     }
594    
595 dpavlin 57 /* get hints */
596     hints = est_noderes_hints(nres);
597    
598 dpavlin 41 elog(DEBUG1, "pgest_node: found %d hits for %s", resnum, query);
599    
600    
601     values = (char **) palloc(ncols * sizeof(char *));
602    
603     for (i = 0; i < nrows; i++)
604     {
605    
606     /* get result from estraier */
607 dpavlin 51 if (! ( rdoc = est_noderes_get_doc(nres, i) )) {
608 dpavlin 47 elog(INFO, "pgest_node: can't find result %d", i + offset);
609 dpavlin 41 } else {
610     elog(DEBUG1, "URI: %s\n Title: %s\n",
611     est_resdoc_attr(rdoc, "@uri"),
612     est_resdoc_attr(rdoc, "@title")
613     );
614     }
615    
616     /* iterate over results */
617     for (j = 0; j < ncols; j++)
618     {
619     bool isnull;
620 dpavlin 57 char *attr; /* current attribute name */
621     char *hint; /* position of current hint in attribute */
622     char *hint_val;
623 dpavlin 41
624     /* array value of this position */
625     indx[0] = j + attr_dim_lower_bounds[0];
626    
627     dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
628 dpavlin 57 attr = (char *)DirectFunctionCall1(textout, dvalue);
629 dpavlin 41
630 dpavlin 57 if (!isnull && (hint = strstr(attr, HINTS_PREFIX)) != NULL) {
631     /* skip HINTS. prefix */
632     hint += strlen(HINTS_PREFIX);
633    
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 dpavlin 41 else
646     values[j] = NULL;
647     }
648     /* construct the tuple */
649     tuple = BuildTupleFromCStrings(attinmeta, values);
650    
651     /* now store it */
652     tuplestore_puttuple(tupstore, tuple);
653    
654     }
655    
656     tuplestore_donestoring(tupstore);
657     rsinfo->setResult = tupstore;
658    
659     /*
660     * SFRM_Materialize mode expects us to return a NULL Datum. The actual
661     * tuples are in our tuplestore and passed back through
662     * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
663     * that we actually used to build our tuples with, so the caller can
664     * verify we did what it was expecting.
665     */
666     rsinfo->setDesc = tupdesc;
667     MemoryContextSwitchTo(oldcontext);
668    
669     /* delete the node result object */
670     est_noderes_delete(nres);
671    
672     /* 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;
682     }
683    
684     /* make text var from node attr */
685     char *node_attr2text(ESTRESDOC *rdoc, char *attr) {
686     char *val;
687     const char *attrval;
688     int len;
689     int attrlen;
690    
691 dpavlin 47 if (! rdoc) return (Datum) NULL;
692    
693 dpavlin 56 elog(DEBUG1, "doc: %p, attr: %s", rdoc, attr);
694 dpavlin 41
695     if ( (attrval = est_resdoc_attr(rdoc, attr)) && (attrlen = strlen(attrval)) ) {
696     val = (char *) palloc(attrlen * sizeof(char));
697     } else {
698     return (Datum) NULL;
699     }
700    
701     len = strlen(attrval);
702     elog(DEBUG1, "node_attr2text(%s) = '%s' %d bytes", attr, attrval, len);
703    
704     len++;
705     len *= sizeof(char);
706    
707     elog(DEBUG2, "palloc(%d)", len);
708    
709     val = palloc(len);
710    
711     memset(val, 0, len);
712     strncpy(val, attrval, len);
713    
714     elog(DEBUG2, "val=%s", val);
715    
716     return val;
717     }
718    
719 dpavlin 56 /* 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     }

  ViewVC Help
Powered by ViewVC 1.1.26