/[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 56 - (hide annotations)
Thu May 11 15:52:50 2006 UTC (17 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 18049 byte(s)
fix multiple attributes delimited with {{!}}, fix warnings
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    
46 dpavlin 5 /* prototype */
47     char *attr2text(ESTDOC *doc, char *attr);
48 dpavlin 41 char *node_attr2text(ESTRESDOC *rdoc, char *attr);
49 dpavlin 56 void cond_add_attr(ESTCOND *cond, char *attr);
50 dpavlin 1
51    
52     /* work in progress */
53 dpavlin 19 PG_FUNCTION_INFO_V1(pgest_attr);
54     Datum pgest_attr(PG_FUNCTION_ARGS)
55 dpavlin 1 {
56 dpavlin 31 ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(6);
57 dpavlin 25 Oid attr_element_type = ARR_ELEMTYPE(attr_arr);
58     int attr_ndims = ARR_NDIM(attr_arr);
59     int *attr_dim_counts = ARR_DIMS(attr_arr);
60     int *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
61 dpavlin 19 int ncols = 0;
62     int nrows = 0;
63     int indx[MAXDIM];
64 dpavlin 25 int16 attr_len;
65     bool attr_byval;
66     char attr_align;
67 dpavlin 1 ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
68     AttInMetadata *attinmeta;
69     TupleDesc tupdesc;
70 dpavlin 19 Tuplestorestate *tupstore = NULL;
71 dpavlin 1 HeapTuple tuple;
72     MemoryContext per_query_ctx;
73     MemoryContext oldcontext;
74     Datum dvalue;
75     char **values;
76 dpavlin 19 int rsinfo_ncols;
77 dpavlin 1 int i, j;
78 dpavlin 19 /* estvars */
79 dpavlin 25 ESTDB *db;
80     ESTCOND *cond;
81     ESTDOC *doc;
82     int ecode, *est_result, resnum;
83     int limit = 0;
84     int offset = 0;
85    
86 dpavlin 19 char *index_path;
87     char *query;
88     char *attr;
89 dpavlin 31 char *order;
90 dpavlin 1
91 dpavlin 19
92     /* only allow 1D input array */
93 dpavlin 25 if (attr_ndims == 1)
94 dpavlin 19 {
95 dpavlin 25 ncols = attr_dim_counts[0];
96 dpavlin 19 }
97     else
98     ereport(ERROR,
99     (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
100     errmsg("invalid input array"),
101     errdetail("Input array must have 1 dimension")));
102    
103 dpavlin 1 /* check to see if caller supports us returning a tuplestore */
104     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 dpavlin 19 /* get info about element type needed to construct the array */
111 dpavlin 25 get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
112 dpavlin 19
113 dpavlin 1 /* get the requested return tuple description */
114     tupdesc = rsinfo->expectedDesc;
115 dpavlin 19 rsinfo_ncols = tupdesc->natts;
116 dpavlin 1
117     /*
118     * The requested tuple description better match up with the array
119     * we were given.
120     */
121 dpavlin 19 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 dpavlin 1 /* OK, use it */
128     attinmeta = TupleDescGetAttInMetadata(tupdesc);
129    
130     /* Now go to work */
131     rsinfo->returnMode = SFRM_Materialize;
132    
133     per_query_ctx = fcinfo->flinfo->fn_mcxt;
134     oldcontext = MemoryContextSwitchTo(per_query_ctx);
135    
136     /* initialize our tuplestore */
137     tupstore = tuplestore_begin_heap(true, false, SortMem);
138    
139 dpavlin 19
140     /* take rest of arguments from function */
141    
142     /* 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     /* query string */
152 dpavlin 31 if (PG_ARGISNULL(1)) {
153 dpavlin 19 query = "";
154     } else {
155     query = _textout(PG_GETARG_TEXT_P(1));
156     }
157    
158     /* atribute filter */
159     if (PG_ARGISNULL(2)) {
160     attr = "";
161     } else {
162     attr = _textout(PG_GETARG_TEXT_P(2));
163     }
164 dpavlin 31
165     /* sort order */
166     if (PG_ARGISNULL(3)) {
167     order = "";
168     } else {
169     order = _textout(PG_GETARG_TEXT_P(3));
170     }
171 dpavlin 19
172 dpavlin 31
173 dpavlin 19 /* limit */
174 dpavlin 31 if (PG_ARGISNULL(4)) {
175 dpavlin 19 limit = 0;
176     } else {
177 dpavlin 31 limit = PG_GETARG_INT32(4);
178 dpavlin 19 }
179    
180     /* offset */
181 dpavlin 31 if (PG_ARGISNULL(5)) {
182 dpavlin 19 offset = 0;
183     } else {
184 dpavlin 31 offset = PG_GETARG_INT32(5);
185 dpavlin 19 }
186    
187    
188     /* open the database */
189     elog(DEBUG1, "pgest_attr: est_db_open(%s)", index_path);
190    
191     if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){
192     ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
193     errmsg("est_db_open: can't open %s: %d", index_path, ecode),
194     errdetail(est_err_msg(ecode))));
195     }
196    
197 dpavlin 20 elog(DEBUG1, "pgest_attr: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(2) ? "NULL" : attr), limit, offset);
198 dpavlin 19
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 dpavlin 40 elog(DEBUG1,"attributes: %s", attr);
212 dpavlin 56 cond_add_attr(cond, attr);
213 dpavlin 19 }
214    
215 dpavlin 31 /* 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 dpavlin 38 if (limit) {
222     elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
223     est_cond_set_max(cond, limit + offset);
224     }
225    
226 dpavlin 19 /* 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 dpavlin 31 nrows = limit;
237 dpavlin 19 } else {
238     nrows = resnum - offset;
239     }
240    
241    
242     elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);
243    
244 dpavlin 1 values = (char **) palloc(ncols * sizeof(char *));
245    
246     for (i = 0; i < nrows; i++)
247     {
248 dpavlin 19
249     /* get result from estraier */
250     if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {
251 dpavlin 47 elog(INFO, "pgest_attr: can't find result %d", i + offset);
252 dpavlin 19 } else {
253     elog(DEBUG1, "URI: %s\n Title: %s\n",
254     est_doc_attr(doc, "@uri"),
255     est_doc_attr(doc, "@title")
256     );
257     }
258    
259     /* iterate over results */
260 dpavlin 1 for (j = 0; j < ncols; j++)
261     {
262 dpavlin 19 bool isnull;
263    
264     /* array value of this position */
265 dpavlin 25 indx[0] = j + attr_dim_lower_bounds[0];
266 dpavlin 19
267 dpavlin 25 dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
268 dpavlin 19
269     if (!isnull && doc)
270     values[j] = DatumGetCString(
271     attr2text(doc,
272 dpavlin 20 (char *)DirectFunctionCall1(textout, dvalue)
273 dpavlin 19 ));
274     else
275     values[j] = NULL;
276 dpavlin 1 }
277     /* construct the tuple */
278     tuple = BuildTupleFromCStrings(attinmeta, values);
279    
280     /* now store it */
281     tuplestore_puttuple(tupstore, tuple);
282 dpavlin 19
283     /* delete estraier document object */
284 dpavlin 47 if (doc) est_doc_delete(doc);
285 dpavlin 1 }
286    
287     tuplestore_donestoring(tupstore);
288     rsinfo->setResult = tupstore;
289    
290     /*
291     * SFRM_Materialize mode expects us to return a NULL Datum. The actual
292     * tuples are in our tuplestore and passed back through
293     * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
294     * that we actually used to build our tuples with, so the caller can
295     * verify we did what it was expecting.
296     */
297     rsinfo->setDesc = tupdesc;
298     MemoryContextSwitchTo(oldcontext);
299    
300 dpavlin 31 est_cond_delete(cond);
301    
302 dpavlin 19 if(!est_db_close(db, &ecode)){
303     ereport(ERROR, (errcode(ERRCODE_IO_ERROR),
304     errmsg("est_db_close: %d", ecode),
305     errdetail(est_err_msg(ecode))));
306     }
307    
308 dpavlin 1 return (Datum) 0;
309     }
310    
311    
312     /* make text var from attr */
313     char *attr2text(ESTDOC *doc, char *attr) {
314     char *val;
315     const char *attrval;
316     int len;
317 dpavlin 4 int attrlen;
318 dpavlin 1
319 dpavlin 47 if (! doc) return (Datum) NULL;
320    
321 dpavlin 56 elog(DEBUG1, "doc: %p, attr: %s", doc, attr);
322 dpavlin 1
323 dpavlin 4 if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {
324     val = (char *) palloc(attrlen * sizeof(char));
325 dpavlin 1 } else {
326     return (Datum) NULL;
327     }
328    
329     len = strlen(attrval);
330 dpavlin 2 elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);
331 dpavlin 1
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 dpavlin 41 /*
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 dpavlin 48 /* select * from pgest( */
354     #define _arg_node_uri 0
355     #define _arg_login 1
356     #define _arg_passwd 2
357 dpavlin 49 #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 dpavlin 48 /* as (foo text, ... ); */
365    
366    
367 dpavlin 41 PG_FUNCTION_INFO_V1(pgest_node);
368     Datum pgest_node(PG_FUNCTION_ARGS)
369     {
370 dpavlin 48 ArrayType *attr_arr = PG_GETARG_ARRAYTYPE_P(_arg_attr_array);
371 dpavlin 41 Oid attr_element_type = ARR_ELEMTYPE(attr_arr);
372     int attr_ndims = ARR_NDIM(attr_arr);
373     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;
382     AttInMetadata *attinmeta;
383     TupleDesc tupdesc;
384     Tuplestorestate *tupstore = NULL;
385     HeapTuple tuple;
386     MemoryContext per_query_ctx;
387     MemoryContext oldcontext;
388     Datum dvalue;
389     char **values;
390     int rsinfo_ncols;
391     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 dpavlin 49 int depth = 0;
401 dpavlin 41
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 */
421     if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
422     ereport(ERROR,
423     (errcode(ERRCODE_SYNTAX_ERROR),
424     errmsg("materialize mode required, but it is not " \
425     "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 */
431     tupdesc = rsinfo->expectedDesc;
432     rsinfo_ncols = tupdesc->natts;
433    
434     /*
435     * The requested tuple description better match up with the array
436     * 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 */
445     attinmeta = TupleDescGetAttInMetadata(tupdesc);
446    
447     /* Now go to work */
448     rsinfo->returnMode = SFRM_Materialize;
449    
450     per_query_ctx = fcinfo->flinfo->fn_mcxt;
451     oldcontext = MemoryContextSwitchTo(per_query_ctx);
452    
453     /* initialize our tuplestore */
454     tupstore = tuplestore_begin_heap(true, false, SortMem);
455    
456    
457     /* take rest of arguments from function */
458    
459     /* node URL */
460 dpavlin 48 if (PG_ARGISNULL(_arg_node_uri)) {
461 dpavlin 41 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 dpavlin 48 node_url = _textout(PG_GETARG_TEXT_P(_arg_node_uri));
467 dpavlin 41
468     /* login and password */
469 dpavlin 48 if (PG_ARGISNULL(_arg_login) || PG_ARGISNULL(_arg_passwd)) {
470 dpavlin 41 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 dpavlin 48 user = _textout(PG_GETARG_TEXT_P(_arg_login));
476     passwd = _textout(PG_GETARG_TEXT_P(_arg_passwd));
477 dpavlin 41
478 dpavlin 49 /* depth of search */
479     if (PG_ARGISNULL(_arg_depth)) {
480     depth = 0;
481     } else {
482     depth = PG_GETARG_INT32(_arg_depth);
483     }
484    
485 dpavlin 41 /* query string */
486 dpavlin 48 if (PG_ARGISNULL(_arg_query)) {
487 dpavlin 41 query = "";
488     } else {
489 dpavlin 48 query = _textout(PG_GETARG_TEXT_P(_arg_query));
490 dpavlin 41 }
491    
492     /* atribute filter */
493 dpavlin 48 if (PG_ARGISNULL(_arg_attr)) {
494 dpavlin 41 attr = "";
495     } else {
496 dpavlin 48 attr = _textout(PG_GETARG_TEXT_P(_arg_attr));
497 dpavlin 41 }
498    
499     /* sort order */
500 dpavlin 48 if (PG_ARGISNULL(_arg_order)) {
501 dpavlin 41 order = "";
502     } else {
503 dpavlin 48 order = _textout(PG_GETARG_TEXT_P(_arg_order));
504 dpavlin 41 }
505    
506    
507     /* limit */
508 dpavlin 48 if (PG_ARGISNULL(_arg_limit)) {
509 dpavlin 41 limit = 0;
510     } else {
511 dpavlin 48 limit = PG_GETARG_INT32(_arg_limit);
512 dpavlin 41 }
513    
514     /* offset */
515 dpavlin 48 if (PG_ARGISNULL(_arg_offset)) {
516 dpavlin 41 offset = 0;
517     } else {
518 dpavlin 48 offset = PG_GETARG_INT32(_arg_offset);
519 dpavlin 41 }
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 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);
533 dpavlin 41
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 dpavlin 48 if (! PG_ARGISNULL(_arg_query) && strlen(query) > 0)
542 dpavlin 41 est_cond_set_phrase(cond, query);
543    
544     /* minimum valid attribute length is 10: @a STREQ a */
545 dpavlin 48 if (! PG_ARGISNULL(_arg_attr) && strlen(attr) >= 10) {
546 dpavlin 41 elog(DEBUG1,"attributes: %s", attr);
547 dpavlin 56 cond_add_attr(cond, attr);
548 dpavlin 41 }
549    
550     /* set the search phrase to the search condition object */
551 dpavlin 48 if (! PG_ARGISNULL(_arg_order) && strlen(order) > 0) {
552 dpavlin 41 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 dpavlin 51 if (offset) {
562     elog(DEBUG1,"est_cond_set_skip(%d)", offset);
563     est_cond_set_skip(cond, offset);
564     }
565    
566 dpavlin 41 /* get the result of search */
567 dpavlin 49 nres = est_node_search(node, cond, depth);
568 dpavlin 41
569 dpavlin 44 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 dpavlin 41 /* 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 *));
597    
598     for (i = 0; i < nrows; i++)
599     {
600    
601     /* get result from estraier */
602 dpavlin 51 if (! ( rdoc = est_noderes_get_doc(nres, i) )) {
603 dpavlin 47 elog(INFO, "pgest_node: can't find result %d", i + offset);
604 dpavlin 41 } 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++)
613     {
614     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 */
630     tuple = BuildTupleFromCStrings(attinmeta, values);
631    
632     /* now store it */
633     tuplestore_puttuple(tupstore, tuple);
634    
635     }
636    
637     tuplestore_donestoring(tupstore);
638     rsinfo->setResult = tupstore;
639    
640     /*
641     * SFRM_Materialize mode expects us to return a NULL Datum. The actual
642     * tuples are in our tuplestore and passed back through
643     * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
644     * that we actually used to build our tuples with, so the caller can
645     * verify we did what it was expecting.
646     */
647     rsinfo->setDesc = tupdesc;
648     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;
663     }
664    
665     /* make text var from node attr */
666     char *node_attr2text(ESTRESDOC *rdoc, char *attr) {
667     char *val;
668     const char *attrval;
669     int len;
670     int attrlen;
671    
672 dpavlin 47 if (! rdoc) return (Datum) NULL;
673    
674 dpavlin 56 elog(DEBUG1, "doc: %p, attr: %s", rdoc, attr);
675 dpavlin 41
676     if ( (attrval = est_resdoc_attr(rdoc, attr)) && (attrlen = strlen(attrval)) ) {
677     val = (char *) palloc(attrlen * sizeof(char));
678     } else {
679     return (Datum) NULL;
680     }
681    
682     len = strlen(attrval);
683     elog(DEBUG1, "node_attr2text(%s) = '%s' %d bytes", attr, attrval, len);
684    
685     len++;
686     len *= sizeof(char);
687    
688     elog(DEBUG2, "palloc(%d)", len);
689    
690     val = palloc(len);
691    
692     memset(val, 0, len);
693     strncpy(val, attrval, len);
694    
695     elog(DEBUG2, "val=%s", val);
696    
697     return val;
698     }
699    
700 dpavlin 56 /* parse attributes and add them to confition */
701     void cond_add_attr(ESTCOND *cond, char *attr) {
702     char *next;
703     char *curr_attr;
704     while ( strlen(attr) > 0 ) {
705     printf("len [%s] = %d\n", attr, strlen(attr));
706     if ((next = strstr(attr, ATTR_DELIMITER)) != NULL) {
707     curr_attr = palloc( next - attr + 1 );
708     memcpy(curr_attr, attr, next-attr);
709     curr_attr[next-attr] = '\0';
710     next += strlen(ATTR_DELIMITER);
711     } else {
712     next = "";
713     curr_attr = attr;
714     }
715     elog(DEBUG1, "est_cond_add_attr(%s)", curr_attr);
716     est_cond_add_attr(cond, curr_attr);
717     attr = next;
718     }
719     }

  ViewVC Help
Powered by ViewVC 1.1.26