/[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 4 - (hide annotations)
Fri May 20 18:45:01 2005 UTC (18 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 8873 byte(s)
bugfix: return null for 0 sized attributes

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     * - example002.c from Hyper Estraier (GPL)
18     * - _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     #include "miscadmin.h"
29     #include <estraier.h>
30     #include <cabin.h>
31    
32     #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
33     #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))
34     #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
35     #define GET_TEXT(cstrp) DatumGetTextP(DirectFunctionCall1(textin, CStringGetDatum(cstrp)))
36    
37    
38     ESTDB *db;
39     ESTCOND *cond;
40     ESTDOC *doc;
41     const CBLIST *texts;
42     int ecode, *est_result, resnum, i, j;
43 dpavlin 3 int limit = 0;
44     int offset = 0;
45 dpavlin 1
46     /* define PostgreSQL v1 function */
47     PG_FUNCTION_INFO_V1(pgest);
48     Datum pgest(PG_FUNCTION_ARGS) {
49    
50     FuncCallContext *funcctx;
51     int call_cntr;
52     int max_calls;
53     TupleDesc tupdesc;
54     TupleTableSlot *slot;
55     AttInMetadata *attinmeta;
56     char *index_path;
57     char *query;
58    
59     /* stuff done only on the first call of the function */
60     if (SRF_IS_FIRSTCALL()) {
61     MemoryContext oldcontext;
62    
63     /* take arguments from function */
64     //index_path = _textout(PG_GETARG_TEXT_P(0));
65     index_path = _textout(PG_GETARG_TEXT_P(0));
66     query = _textout(PG_GETARG_TEXT_P(1));
67 dpavlin 3 limit = PG_GETARG_INT32(2);
68     offset = PG_GETARG_INT32(3);
69 dpavlin 1
70     /* create a function context for cross-call persistence */
71     funcctx = SRF_FIRSTCALL_INIT();
72    
73     /* switch to memory context appropriate for multiple function calls */
74     oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
75    
76     /* open the database */
77     elog(DEBUG1, "pgest: est_db_open(%s)", index_path);
78    
79     if(!(db = est_db_open(index_path, ESTDBREADER, &ecode))){
80     elog(ERROR, "est_db_open: can't open %s [%d]: %s", index_path, ecode, est_err_msg(ecode));
81     SRF_RETURN_DONE(funcctx);
82     }
83    
84 dpavlin 3 elog(INFO, "pgest: query=%s limit %d offset %d", query, limit, offset);
85 dpavlin 1
86     /* create a search condition object */
87     if (!(cond = est_cond_new())) {
88     elog(INFO, "pgest: est_cond_new failed");
89     SRF_RETURN_DONE(funcctx);
90     }
91    
92     /* set the search phrase to the search condition object */
93     est_cond_set_phrase(cond, query);
94    
95     /* get the result of search */
96     est_result = est_db_search(db, cond, &resnum, NULL);
97    
98     /* total number of tuples to be returned */
99     funcctx->max_calls = resnum;
100    
101     /* check if results exists */
102     if ( 0 == funcctx->max_calls )
103     elog(INFO, "pgest: no results for: %s", query );
104    
105 dpavlin 2 elog(DEBUG1, "pgest: found %d hits for %s", funcctx->max_calls, query);
106 dpavlin 1
107     /* Build a tuple description for a __pgest tuple */
108     tupdesc = RelationNameGetTupleDesc("__pgest");
109    
110     /* allocate a slot for a tuple with this tupdesc */
111     slot = TupleDescGetSlot(tupdesc);
112    
113     /* assign slot to function context */
114     funcctx->slot = slot;
115    
116     /*
117     * generate attribute metadata needed later to produce tuples from raw
118     * C strings
119     */
120     attinmeta = TupleDescGetAttInMetadata(tupdesc);
121     funcctx->attinmeta = attinmeta;
122    
123     MemoryContextSwitchTo(oldcontext);
124    
125 dpavlin 2 elog(DEBUG1, "SRF_IS_FIRSTCALL done");
126 dpavlin 1 }
127    
128     /* stuff done on every call of the function */
129     funcctx = SRF_PERCALL_SETUP();
130    
131     call_cntr = funcctx->call_cntr;
132     max_calls = funcctx->max_calls;
133     slot = funcctx->slot;
134     attinmeta = funcctx->attinmeta;
135 dpavlin 3
136     if (limit && call_cntr > limit - 1) {
137     elog(INFO, "call_cntr: %d limit: %d", call_cntr, limit);
138     SRF_RETURN_DONE(funcctx);
139     }
140    
141 dpavlin 1 if (call_cntr < max_calls) {
142     char **values;
143     HeapTuple tuple;
144     Datum result;
145    
146 dpavlin 2 elog(DEBUG1, "pgest: loop count %d", call_cntr);
147 dpavlin 1
148     if (! est_result) {
149     elog(ERROR, "pgest: no estraier results");
150     SRF_RETURN_DONE(funcctx);
151     }
152    
153     /*
154     * Prepare a values array for storage in our slot.
155     * This should be an array of C strings which will
156     * be processed later by the type input functions.
157     */
158    
159 dpavlin 3 if (doc = est_db_get_doc(db, est_result[call_cntr + offset], 0)) {
160 dpavlin 1
161 dpavlin 2 elog(DEBUG1, "URI: %s\n Title: %s\n",
162 dpavlin 1 est_doc_attr(doc, "@uri"),
163     est_doc_attr(doc, "@title")
164     );
165    
166     values = (char **) palloc(4 * sizeof(char *));
167    
168     // values[0] = (char *) palloc(strlen(_estval) * sizeof(char));
169    
170     values[0] = attr2text(doc,"@id");
171     values[1] = attr2text(doc,"@uri");
172     values[2] = attr2text(doc,"@title");
173     values[3] = attr2text(doc,"@type");
174    
175     /* destloy the document object */
176     elog(DEBUG2, "est_doc_delete");
177     est_doc_delete(doc);
178     } else {
179     elog(INFO, "no result from estraier");
180     values[0] = NULL;
181     values[1] = NULL;
182     values[2] = NULL;
183     values[3] = NULL;
184     }
185    
186    
187     elog(DEBUG2, "build tuple");
188     /* build a tuple */
189     tuple = BuildTupleFromCStrings(attinmeta, values);
190    
191     elog(DEBUG2, "make tuple into datum");
192     /* make the tuple into a datum */
193     result = TupleGetDatum(slot, tuple);
194    
195     elog(DEBUG2, "cleanup");
196     /* clean up ? */
197     /*
198     pfree(values[0]);
199     pfree(values[1]);
200     pfree(values[2]);
201     pfree(values[3]);
202     pfree(values);
203     */
204    
205     elog(DEBUG2, "cleanup over");
206    
207     SRF_RETURN_NEXT(funcctx, result);
208     } else {
209 dpavlin 2 elog(DEBUG1, "loop over");
210 dpavlin 1
211     if(!est_db_close(db, &ecode)){
212     elog(INFO, "est_db_close error: %s", est_err_msg(ecode));
213     }
214    
215     /* do when there is no more left */
216     SRF_RETURN_DONE(funcctx);
217     }
218     }
219    
220     /* work in progress */
221     PG_FUNCTION_INFO_V1(pgest2);
222     Datum pgest2(PG_FUNCTION_ARGS)
223     {
224     int nrows = 3;
225     int16 typlen;
226     bool typbyval;
227     char typalign;
228     ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
229     AttInMetadata *attinmeta;
230     TupleDesc tupdesc;
231     Tuplestorestate *tupstore = NULL;
232     HeapTuple tuple;
233     MemoryContext per_query_ctx;
234     MemoryContext oldcontext;
235     Datum dvalue;
236     char **values;
237     int ncols;
238     int i, j;
239    
240     /* check to see if caller supports us returning a tuplestore */
241     if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
242     ereport(ERROR,
243     (errcode(ERRCODE_SYNTAX_ERROR),
244     errmsg("materialize mode required, but it is not " \
245     "allowed in this context")));
246    
247     /* get the requested return tuple description */
248     tupdesc = rsinfo->expectedDesc;
249     ncols = tupdesc->natts;
250    
251     /*
252     * The requested tuple description better match up with the array
253     * we were given.
254     */
255     /* OK, use it */
256     attinmeta = TupleDescGetAttInMetadata(tupdesc);
257    
258     /* Now go to work */
259     rsinfo->returnMode = SFRM_Materialize;
260    
261     per_query_ctx = fcinfo->flinfo->fn_mcxt;
262     oldcontext = MemoryContextSwitchTo(per_query_ctx);
263    
264     /* initialize our tuplestore */
265     tupstore = tuplestore_begin_heap(true, false, SortMem);
266    
267     values = (char **) palloc(ncols * sizeof(char *));
268    
269     for (i = 0; i < nrows; i++)
270     {
271     for (j = 0; j < ncols; j++)
272     {
273     values[j] = DatumGetCString( "foo" );
274     }
275     /* construct the tuple */
276     tuple = BuildTupleFromCStrings(attinmeta, values);
277    
278     /* now store it */
279     tuplestore_puttuple(tupstore, tuple);
280     }
281    
282     tuplestore_donestoring(tupstore);
283     rsinfo->setResult = tupstore;
284    
285     /*
286     * SFRM_Materialize mode expects us to return a NULL Datum. The actual
287     * tuples are in our tuplestore and passed back through
288     * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
289     * that we actually used to build our tuples with, so the caller can
290     * verify we did what it was expecting.
291     */
292     rsinfo->setDesc = tupdesc;
293     MemoryContextSwitchTo(oldcontext);
294    
295     return (Datum) 0;
296     }
297    
298    
299     /* make text var from attr */
300     char *attr2text(ESTDOC *doc, char *attr) {
301     char *val;
302     const char *attrval;
303     int len;
304 dpavlin 4 int attrlen;
305 dpavlin 1
306 dpavlin 2 elog(DEBUG1, "doc: %08x, attr: %s", doc, attr);
307 dpavlin 1
308 dpavlin 4 if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {
309     val = (char *) palloc(attrlen * sizeof(char));
310 dpavlin 1 } else {
311     return (Datum) NULL;
312     }
313    
314     len = strlen(attrval);
315 dpavlin 2 elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);
316 dpavlin 1
317     len++;
318     len *= sizeof(char);
319    
320     elog(DEBUG2, "palloc(%d)", len);
321    
322     val = palloc(len);
323    
324     memset(val, 0, len);
325     strncpy(val, attrval, len);
326    
327     elog(DEBUG2, "val=%s", val);
328    
329     return val;
330     }
331    
332     /* make integer variable from property */
333     /*
334     char *prop2int(SW_RESULT sw_res, char *propname) {
335     char *val;
336     unsigned long prop;
337     int len;
338    
339     elog(DEBUG2, "prop2int(%s)", propname);
340    
341     prop = estResultPropertyULong( sw_res, propname );
342     if (error_or_abort( est_handle )) return NULL;
343    
344     elog(DEBUG1, "prop2int(%s) = %lu", propname, prop);
345    
346     len = 128 * sizeof(char);
347     elog(DEBUG2, "palloc(%d)", len);
348    
349     val = palloc(len);
350     memset(val, 0, len);
351    
352     snprintf(val, len, "%lu", prop);
353    
354     elog(DEBUG2, "val=%s", val);
355    
356     return val;
357     }
358     */

  ViewVC Help
Powered by ViewVC 1.1.26