Logo Search packages:      
Sourcecode: psqlodbc version File versions

tuplelist.c

/*--------
 * Module:              tuplelist.c
 *
 * Description:         This module contains functions for creating a manual
 *                            result set (the TupleList) and retrieving data from
 *                            it for a specific row/column.
 *
 * Classes:             TupleListClass (Functions prefix: "TL_")
 *
 * API functions: none
 *
 * Comments:            See "notice.txt" for copyright and license information.
 *--------
 */

#include "tuplelist.h"

#include <stdlib.h>
#include "tuple.h"


TupleListClass *
TL_Constructor(UInt4 fieldcnt)
{
      TupleListClass *rv;

      mylog("in TL_Constructor\n");

      rv = (TupleListClass *) malloc(sizeof(TupleListClass));
      if (rv)
      {
            rv->num_fields = fieldcnt;
            rv->num_tuples = 0;
            rv->list_start = NULL;
            rv->list_end = NULL;
            rv->lastref = NULL;
            rv->last_indexed = -1;
      }

      mylog("exit TL_Constructor\n");

      return rv;
}


void
TL_Destructor(TupleListClass *self)
{
      int               lf;
      TupleNode  *node,
                     *tp;

      mylog("TupleList: in DESTRUCTOR\n");

      node = self->list_start;
      while (node != NULL)
      {
            for (lf = 0; lf < self->num_fields; lf++)
                  if (node->tuple[lf].value != NULL)
                        free(node->tuple[lf].value);
            tp = node->next;
            free(node);
            node = tp;
      }

      free(self);

      mylog("TupleList: exit DESTRUCTOR\n");
}


void *
TL_get_fieldval(TupleListClass *self, Int4 tupleno, Int2 fieldno)
{
      Int4        lf;
      Int4        delta,
                        from_end;
      char        end_is_closer,
                        start_is_closer;
      TupleNode  *rv;

      if (self->last_indexed == -1)
            /* we have an empty tuple list */
            return NULL;

      /* some more sanity checks */
      if ((tupleno >= self->num_tuples) || (tupleno < 0))
            /* illegal tuple number range */
            return NULL;

      if ((fieldno >= self->num_fields) || (fieldno < 0))
            /* illegel field number range */
            return NULL;

      /*
       * check if we are accessing the same tuple that was used in the last
       * fetch (e.g: for fetching all the fields one after another. Do this
       * to speed things up
       */
      if (tupleno == self->last_indexed)
            return self->lastref->tuple[fieldno].value;

      /* now for the tricky part... */

      /*
       * Since random access is quite inefficient for linked lists we use
       * the lastref pointer that points to the last element referenced by a
       * get_fieldval() call in conjunction with the its index number that
       * is stored in last_indexed. (So we use some locality of reference
       * principle to speed things up)
       */

      delta = tupleno - self->last_indexed;
      /* if delta is positive, we have to go forward */

      /*
       * now check if we are closer to the start or the end of the list than
       * to our last_indexed pointer
       */
      from_end = (self->num_tuples - 1) - tupleno;

      start_is_closer = labs(delta) > tupleno;

      /*
       * true if we are closer to the start of the list than to the
       * last_indexed pointer
       */

      end_is_closer = labs(delta) > from_end;
      /* true if we are closer at the end of the list */

      if (end_is_closer)
      {
            /* scanning from the end is the shortest way. so we do that... */
            rv = self->list_end;
            for (lf = 0; lf < from_end; lf++)
                  rv = rv->prev;
      }
      else if (start_is_closer)
      {
            /*
             * the shortest way is to start the search from the head of the
             * list
             */
            rv = self->list_start;
            for (lf = 0; lf < tupleno; lf++)
                  rv = rv->next;
      }
      else
      {
            /* the closest way is starting from our lastref - pointer */
            rv = self->lastref;

            /*
             * at first determine whether we have to search forward or
             * backwards
             */
            if (delta < 0)
            {
                  /* we have to search backwards */
                  for (lf = 0; lf < (-1) * delta; lf++)
                        rv = rv->prev;
            }
            else
            {
                  /* ok, we have to search forward... */
                  for (lf = 0; lf < delta; lf++)
                        rv = rv->next;
            }
      }

      /*
       * now we have got our return pointer, so update the lastref and the
       * last_indexed values
       */
      self->lastref = rv;
      self->last_indexed = tupleno;

      return rv->tuple[fieldno].value;
}


char
TL_add_tuple(TupleListClass *self, TupleNode *new_field)
{
      /*
       * we append the tuple at the end of the doubly linked list of the
       * tuples we have already read in
       */

      new_field->prev = NULL;
      new_field->next = NULL;

      if (self->list_start == NULL)
      {
            /* the list is empty, we have to add the first tuple */
            self->list_start = new_field;
            self->list_end = new_field;
            self->lastref = new_field;
            self->last_indexed = 0;
      }
      else
      {
            /*
             * there is already an element in the list, so add the new one at
             * the end of the list
             */
            self->list_end->next = new_field;
            new_field->prev = self->list_end;
            self->list_end = new_field;
      }
      self->num_tuples++;

      /* this method of building a list cannot fail, so we return 1 */
      return 1;
}

Generated by  Doxygen 1.6.0   Back to index