/[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 5 - (hide annotations)
Fri May 20 19:44:09 2005 UTC (18 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 9308 byte(s)
added attribute to function, fixed warnings, fixed limit and offset

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

  ViewVC Help
Powered by ViewVC 1.1.26