/[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 1 - (hide annotations)
Fri May 20 12:19:05 2005 UTC (18 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 8556 byte(s)
initial import of API between Estraier and PostgreSQL

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

  ViewVC Help
Powered by ViewVC 1.1.26