/[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 1 - (show 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 /*
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