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

Contents of /trunk/pgest.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3 - (show annotations)
Fri May 20 16:11:38 2005 UTC (18 years, 11 months ago) by dpavlin
File MIME type: text/plain
File size: 8832 byte(s)
added limit and offset

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 int limit = 0;
44 int offset = 0;
45
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 limit = PG_GETARG_INT32(2);
68 offset = PG_GETARG_INT32(3);
69
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 elog(INFO, "pgest: query=%s limit %d offset %d", query, limit, offset);
85
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 elog(DEBUG1, "pgest: found %d hits for %s", funcctx->max_calls, query);
106
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 elog(DEBUG1, "SRF_IS_FIRSTCALL done");
126 }
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
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 if (call_cntr < max_calls) {
142 char **values;
143 HeapTuple tuple;
144 Datum result;
145
146 elog(DEBUG1, "pgest: loop count %d", call_cntr);
147
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 if (doc = est_db_get_doc(db, est_result[call_cntr + offset], 0)) {
160
161 elog(DEBUG1, "URI: %s\n Title: %s\n",
162 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 elog(DEBUG1, "loop over");
210
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
305 elog(DEBUG1, "doc: %08x, attr: %s", doc, attr);
306
307 if (attrval = est_doc_attr(doc, attr)) {
308 val = (char *) palloc(strlen(attrval) * sizeof(char));
309 } else {
310 return (Datum) NULL;
311 }
312
313 len = strlen(attrval);
314 elog(DEBUG1, "attr2text(%s) = '%s' %d bytes", attr, attrval, len);
315
316 len++;
317 len *= sizeof(char);
318
319 elog(DEBUG2, "palloc(%d)", len);
320
321 val = palloc(len);
322
323 memset(val, 0, len);
324 strncpy(val, attrval, len);
325
326 elog(DEBUG2, "val=%s", val);
327
328 return val;
329 }
330
331 /* make integer variable from property */
332 /*
333 char *prop2int(SW_RESULT sw_res, char *propname) {
334 char *val;
335 unsigned long prop;
336 int len;
337
338 elog(DEBUG2, "prop2int(%s)", propname);
339
340 prop = estResultPropertyULong( sw_res, propname );
341 if (error_or_abort( est_handle )) return NULL;
342
343 elog(DEBUG1, "prop2int(%s) = %lu", propname, prop);
344
345 len = 128 * sizeof(char);
346 elog(DEBUG2, "palloc(%d)", len);
347
348 val = palloc(len);
349 memset(val, 0, len);
350
351 snprintf(val, len, "%lu", prop);
352
353 elog(DEBUG2, "val=%s", val);
354
355 return val;
356 }
357 */

  ViewVC Help
Powered by ViewVC 1.1.26