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

Diff of /trunk/pgest.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 40 by dpavlin, Sat Sep 10 18:51:13 2005 UTC revision 48 by dpavlin, Thu Oct 20 16:24:26 2005 UTC
# Line 14  Line 14 
14   *   *
15   * Based on:   * Based on:
16   * - C example from PostgreSQL documentation (BSD licence)   * - C example from PostgreSQL documentation (BSD licence)
17   * - example002.c from Hyper Estraier (GPL)   * - coreexample002.c and nodeexample002.c from Hyper Estraier (GPL)
18   * - _textin/_textout from pgcurl.c (LGPL)   * - _textin/_textout from pgcurl.c (LGPL)
19   *   *
20   * This code is licenced under GPL   * This code is licenced under GPL
# Line 28  Line 28 
28  #include "miscadmin.h"  #include "miscadmin.h"
29  #include <estraier.h>  #include <estraier.h>
30  #include <cabin.h>  #include <cabin.h>
31    #include <estnode.h>
32    
33  #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))  #define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
34  #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))  #define _textout(str) DatumGetPointer(DirectFunctionCall1(textout, PointerGetDatum(str)))
# Line 43  Line 44 
44    
45  /* prototype */  /* prototype */
46  char *attr2text(ESTDOC *doc, char *attr);  char *attr2text(ESTDOC *doc, char *attr);
47    char *node_attr2text(ESTRESDOC *rdoc, char *attr);
48    
49    
50  /* work in progress */  /* work in progress */
# Line 244  Datum pgest_attr(PG_FUNCTION_ARGS) Line 246  Datum pgest_attr(PG_FUNCTION_ARGS)
246    
247          elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);          elog(DEBUG1, "pgest_attr: found %d hits for %s", resnum, query);
248    
   
249          values = (char **) palloc(ncols * sizeof(char *));          values = (char **) palloc(ncols * sizeof(char *));
250    
251          for (i = 0; i < nrows; i++)          for (i = 0; i < nrows; i++)
# Line 252  Datum pgest_attr(PG_FUNCTION_ARGS) Line 253  Datum pgest_attr(PG_FUNCTION_ARGS)
253    
254                  /* get result from estraier */                  /* get result from estraier */
255                  if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {                  if (! ( doc = est_db_get_doc(db, est_result[i + offset], 0)) ) {
256                          elog(INFO, "can't find result %d", i + offset);                          elog(INFO, "pgest_attr: can't find result %d", i + offset);
257                  } else {                  } else {
258                          elog(DEBUG1, "URI: %s\n Title: %s\n",                          elog(DEBUG1, "URI: %s\n Title: %s\n",
259                                  est_doc_attr(doc, "@uri"),                                  est_doc_attr(doc, "@uri"),
# Line 284  Datum pgest_attr(PG_FUNCTION_ARGS) Line 285  Datum pgest_attr(PG_FUNCTION_ARGS)
285                  /* now store it */                  /* now store it */
286                  tuplestore_puttuple(tupstore, tuple);                  tuplestore_puttuple(tupstore, tuple);
287    
   
288                  /* delete estraier document object */                  /* delete estraier document object */
289                  est_doc_delete(doc);                  if (doc) est_doc_delete(doc);
290          }          }
291    
292          tuplestore_donestoring(tupstore);          tuplestore_donestoring(tupstore);
# Line 321  char *attr2text(ESTDOC *doc, char *attr) Line 321  char *attr2text(ESTDOC *doc, char *attr)
321          int len;          int len;
322          int attrlen;          int attrlen;
323    
324            if (! doc) return (Datum) NULL;
325    
326          elog(DEBUG1, "doc: %08x, attr: %s", doc, attr);          elog(DEBUG1, "doc: %08x, attr: %s", doc, attr);
327    
328          if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {          if ( (attrval = est_doc_attr(doc, attr)) && (attrlen = strlen(attrval)) ) {
# Line 334  char *attr2text(ESTDOC *doc, char *attr) Line 336  char *attr2text(ESTDOC *doc, char *attr)
336    
337          len++;          len++;
338          len *= sizeof(char);          len *= sizeof(char);
339    
340            elog(DEBUG2, "palloc(%d)", len);
341    
342            val = palloc(len);
343    
344            memset(val, 0, len);
345            strncpy(val, attrval, len);
346    
347            elog(DEBUG2, "val=%s", val);
348    
349            return val;
350    }
351    
352    /*
353     * variation on theme: use node API which doesn't open index on
354     * every query which is much faster for large indexes
355     *
356     */
357    
358    /* select * from pgest( */
359    #define _arg_node_uri 0
360    #define _arg_login 1
361    #define _arg_passwd 2
362    #define _arg_query 3
363    #define _arg_attr 4
364    #define _arg_order 5
365    #define _arg_limit 6
366    #define _arg_offset 7
367    #define _arg_attr_array 8
368    /* as (foo text, ... ); */
369    
370    
371    PG_FUNCTION_INFO_V1(pgest_node);
372    Datum pgest_node(PG_FUNCTION_ARGS)
373    {
374            ArrayType       *attr_arr = PG_GETARG_ARRAYTYPE_P(_arg_attr_array);
375            Oid             attr_element_type = ARR_ELEMTYPE(attr_arr);
376            int             attr_ndims = ARR_NDIM(attr_arr);
377            int             *attr_dim_counts = ARR_DIMS(attr_arr);
378            int             *attr_dim_lower_bounds = ARR_LBOUND(attr_arr);
379            int             ncols = 0;
380            int             nrows = 0;
381            int             indx[MAXDIM];
382            int16           attr_len;
383            bool            attr_byval;
384            char            attr_align;
385            ReturnSetInfo   *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo;
386            AttInMetadata   *attinmeta;
387            TupleDesc       tupdesc;
388            Tuplestorestate *tupstore = NULL;
389            HeapTuple       tuple;
390            MemoryContext   per_query_ctx;
391            MemoryContext   oldcontext;
392            Datum           dvalue;
393            char            **values;
394            int             rsinfo_ncols;
395            int             i, j;
396            /* estvars */
397            ESTNODE *node;
398            ESTCOND *cond;
399            ESTNODERES *nres;
400            ESTRESDOC *rdoc;
401            const CBLIST *texts;
402            int resnum = 0;
403            int limit = 0;
404            int offset = 0;
405    
406            char            *node_url;
407            char            *user, *passwd;
408            char            *query;
409            char            *attr;
410            char            *order;
411    
412    
413            /* only allow 1D input array */
414            if (attr_ndims == 1)
415            {
416                    ncols = attr_dim_counts[0];
417            }
418            else
419                    ereport(ERROR,
420                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
421                                     errmsg("invalid input array"),
422                                     errdetail("Input array must have 1 dimension")));
423                    
424            /* check to see if caller supports us returning a tuplestore */
425            if (!rsinfo || !(rsinfo->allowedModes & SFRM_Materialize))
426                    ereport(ERROR,
427                                    (errcode(ERRCODE_SYNTAX_ERROR),
428                                     errmsg("materialize mode required, but it is not " \
429                                                    "allowed in this context")));
430    
431            /* get info about element type needed to construct the array */
432            get_typlenbyvalalign(attr_element_type, &attr_len, &attr_byval, &attr_align);
433    
434            /* get the requested return tuple description */
435            tupdesc = rsinfo->expectedDesc;
436            rsinfo_ncols = tupdesc->natts;
437    
438            /*
439             * The requested tuple description better match up with the array
440             * we were given.
441             */
442            if (rsinfo_ncols != ncols)
443                    ereport(ERROR,
444                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
445                                     errmsg("invalid input array"),
446                                     errdetail("Number of elements in array must match number of query specified columns.")));
447    
448            /* OK, use it */
449            attinmeta = TupleDescGetAttInMetadata(tupdesc);
450    
451            /* Now go to work */
452            rsinfo->returnMode = SFRM_Materialize;
453    
454            per_query_ctx = fcinfo->flinfo->fn_mcxt;
455            oldcontext = MemoryContextSwitchTo(per_query_ctx);
456    
457            /* initialize our tuplestore */
458            tupstore = tuplestore_begin_heap(true, false, SortMem);
459    
460    
461            /* take rest of arguments from function */
462    
463            /* node URL */
464            if (PG_ARGISNULL(_arg_node_uri)) {
465                    ereport(ERROR,
466                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
467                                     errmsg("node URL can't be null"),
468                                     errdetail("Node URL must be valid URL to HyperEstraier node")));
469            }
470            node_url = _textout(PG_GETARG_TEXT_P(_arg_node_uri));
471    
472            /* login and password */
473            if (PG_ARGISNULL(_arg_login) || PG_ARGISNULL(_arg_passwd)) {
474                    ereport(ERROR,
475                                    (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
476                                     errmsg("username and password can't be NULL"),
477                                     errdetail("You must specify valid username and password to HyperEstraier node")));
478            }
479            user = _textout(PG_GETARG_TEXT_P(_arg_login));
480            passwd = _textout(PG_GETARG_TEXT_P(_arg_passwd));
481    
482            /* query string */
483            if (PG_ARGISNULL(_arg_query)) {
484                    query = "";
485            } else {
486                    query = _textout(PG_GETARG_TEXT_P(_arg_query));
487            }
488    
489            /* atribute filter */
490            if (PG_ARGISNULL(_arg_attr)) {
491                    attr = "";
492            } else {
493                    attr = _textout(PG_GETARG_TEXT_P(_arg_attr));
494            }
495            
496            /* sort order */
497            if (PG_ARGISNULL(_arg_order)) {
498                    order = "";
499            } else {
500                    order = _textout(PG_GETARG_TEXT_P(_arg_order));
501            }
502    
503    
504            /* limit */
505            if (PG_ARGISNULL(_arg_limit)) {
506                    limit = 0;
507            } else {
508                    limit = PG_GETARG_INT32(_arg_limit);
509            }
510    
511            /* offset */
512            if (PG_ARGISNULL(_arg_offset)) {
513                    offset = 0;
514            } else {
515                    offset = PG_GETARG_INT32(_arg_offset);
516            }
517    
518            /* initialize the network environment */
519            if(!est_init_net_env()){
520                    ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
521                            errmsg("pgest_node: can't create network enviroment")));
522            }
523    
524            /* create the node connection object */
525            elog(DEBUG1, "pgest_node: est_node_new(%s) as %s", node_url, user);
526            node = est_node_new(node_url);
527            est_node_set_auth(node, user, passwd);
528    
529            elog(DEBUG1, "pgest_node: query[%s] attr[%s] limit %d offset %d", query, (PG_ARGISNULL(_arg_attr) ? "NULL" : attr), limit, offset);
530            
531            /* create a search condition object */
532            if (!(cond = est_cond_new())) {
533                    ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
534                            errmsg("pgest_node: est_cond_new failed")));
535            }
536            
537            /* set the search phrase to the search condition object */
538            if (! PG_ARGISNULL(_arg_query) && strlen(query) > 0)
539                    est_cond_set_phrase(cond, query);
540    
541            /* minimum valid attribute length is 10: @a STREQ a */
542            if (! PG_ARGISNULL(_arg_attr) && strlen(attr) >= 10) {
543                    elog(DEBUG1,"attributes: %s", attr);
544                    char *curr_attr;
545                    curr_attr = strtok(attr, ATTR_DELIMITER);
546                    while (curr_attr) {
547                            elog(DEBUG1,"est_cond_add_attr(%s)", curr_attr);
548                            est_cond_add_attr(cond, curr_attr);
549                            curr_attr = strtok(NULL, ATTR_DELIMITER);
550                    }
551            }
552    
553            /* set the search phrase to the search condition object */
554            if (! PG_ARGISNULL(_arg_order) && strlen(order) > 0) {
555                    elog(DEBUG1,"est_cond_set_order(%s)", order);
556                    est_cond_set_order(cond, order);
557            }
558    
559            if (limit) {
560                    elog(DEBUG1,"est_cond_set_max(%d)", limit + offset);
561                    est_cond_set_max(cond, limit + offset);
562            }
563    
564            /* get the result of search */
565            /* FIXME: allow user to specify depath of search */
566            nres = est_node_search(node, cond, 0);
567    
568            if (! nres) {
569                    int status = est_node_status(node);
570                    est_cond_delete(cond);
571                    est_node_delete(node);
572                    est_free_net_env();
573                    ereport(ERROR, (errcode(ERRCODE_QUERY_CANCELED),
574                            errmsg("pgest_node: search failed, node status %d", status)));
575            }
576    
577            /* get number of results */
578            resnum = est_noderes_doc_num(nres);
579    
580            /* check if results exists */
581            if ( 0 == resnum ) {
582                    elog(INFO, "pgest_node: no results for: %s", query );
583            }
584    
585            /* total number of tuples to be returned */
586            if (limit && limit < resnum) {
587                    nrows = limit;
588            } else {
589                    nrows = resnum - offset;
590            }
591    
592    
593            elog(DEBUG1, "pgest_node: found %d hits for %s", resnum, query);
594    
595    
596            values = (char **) palloc(ncols * sizeof(char *));
597    
598            for (i = 0; i < nrows; i++)
599            {
600    
601                    /* get result from estraier */
602                    if (! ( rdoc = est_noderes_get_doc(nres, i + offset) )) {
603                            elog(INFO, "pgest_node: can't find result %d", i + offset);
604                    } else {
605                            elog(DEBUG1, "URI: %s\n Title: %s\n",
606                                    est_resdoc_attr(rdoc, "@uri"),
607                                    est_resdoc_attr(rdoc, "@title")
608                            );
609                    }
610    
611                    /* iterate over results */
612                    for (j = 0; j < ncols; j++)
613                    {
614                            bool    isnull;
615    
616                            /* array value of this position */
617                            indx[0] = j + attr_dim_lower_bounds[0];
618    
619                            dvalue = array_ref(attr_arr, attr_ndims, indx, -1, attr_len, attr_byval, attr_align, &isnull);
620    
621                            if (!isnull && rdoc)
622                                    values[j] = DatumGetCString(
623                                            node_attr2text(rdoc,
624                                                    (char *)DirectFunctionCall1(textout, dvalue)
625                                            ));
626                            else
627                                    values[j] = NULL;
628                    }
629                    /* construct the tuple */
630                    tuple = BuildTupleFromCStrings(attinmeta, values);
631    
632                    /* now store it */
633                    tuplestore_puttuple(tupstore, tuple);
634    
635            }
636    
637            tuplestore_donestoring(tupstore);
638            rsinfo->setResult = tupstore;
639    
640            /*
641             * SFRM_Materialize mode expects us to return a NULL Datum. The actual
642             * tuples are in our tuplestore and passed back through
643             * rsinfo->setResult. rsinfo->setDesc is set to the tuple description
644             * that we actually used to build our tuples with, so the caller can
645             * verify we did what it was expecting.
646             */
647            rsinfo->setDesc = tupdesc;
648            MemoryContextSwitchTo(oldcontext);
649    
650            /* delete the node result object */
651            est_noderes_delete(nres);
652    
653            /* destroy the search condition object */                          
654            est_cond_delete(cond);
655    
656            /* destroy the node object */
657            est_node_delete(node);
658    
659            /* free the networking environment */
660            est_free_net_env();
661    
662            return (Datum) 0;
663    }
664    
665    /* make text var from node attr */
666    char *node_attr2text(ESTRESDOC *rdoc, char *attr) {
667            char *val;
668            const char *attrval;
669            int len;
670            int attrlen;
671    
672            if (! rdoc) return (Datum) NULL;
673    
674            elog(DEBUG1, "doc: %08x, attr: %s", rdoc, attr);
675    
676            if ( (attrval = est_resdoc_attr(rdoc, attr)) && (attrlen = strlen(attrval)) ) {
677                    val = (char *) palloc(attrlen * sizeof(char));
678            } else {
679                    return (Datum) NULL;
680            }
681    
682            len = strlen(attrval);
683            elog(DEBUG1, "node_attr2text(%s) = '%s' %d bytes", attr, attrval, len);
684    
685            len++;
686            len *= sizeof(char);
687    
688          elog(DEBUG2, "palloc(%d)", len);          elog(DEBUG2, "palloc(%d)", len);
689    

Legend:
Removed from v.40  
changed lines
  Added in v.48

  ViewVC Help
Powered by ViewVC 1.1.26