/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  backend.c defines the functions to access the database search output
  markus@mhoenicka.de 6-19-00

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, see <http://www.gnu.org/licenses/>

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <syslog.h>
#include <math.h> /* for log() */
#include <dbi/dbi.h>

#include "refdb.h"
#include "linklist.h"
#include "refdbd.h"
#include "backend.h"
#include "strfncs.h"
#include "dbfncs.h"
#include "risdb.h"
#include "authorinfo.h"
#include "connect.h"
#include "readris.h"
#include "rtfhelper.h"


/* globals */

extern int n_log_level;
extern dbi_result dbi_style_res;
extern char main_db[];

/* this string array is used for author queries. MySQL uses an enum field,
   pgsql and others use an int field to store the author type */
const char author_type_string[2][3][14] = {
  {"\'part\'", "\'publication\'", "\'set\'"},
  {"1", "2", "3"}
};

/* this is the javascript code used to pop up the tooltips in the
   xhtml output of the checkref command */
char checkref_javascript[] = "<script type=\"text/javascript\">\n"
"<!--\n"
"tooltip = null;\n"
"document.onmousemove = updateTOOLTIP;\n"
"function updateTOOLTIP(e) {\n"
"	x = (document.all) ? window.event.x + document.body.scrollLeft : e.pageX;\n"
"	y = (document.all) ? window.event.y + document.body.scrollTop  : e.pageY;\n"
"	if (tooltip != null) {\n"
"		tooltip.style.left = (x + 10) + \"px\";\n"
"		tooltip.style.top 	= (y + 10) + \"px\";\n"
"	}\n"
"}\n"
"\n"
"function showTOOLTIP(id) {\n"
"   tooltip = document.getElementById(id);\n"
"   tooltip.style.display = \"block\"\n"
"}\n"
"\n"
"function hideTOOLTIP() {\n"
"	tooltip.style.display = \"none\";\n"
"}\n"
"//-->\n"
"</script>\n";

/* forward declaration of local functions */
static const char* real_get_periodical(dbi_result dbires, int is_temp, unsigned long long* ptr_frequency);

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  assemble_header(): assembles various html, xhtml, and XML headers

  struct renderinfo* ptr_rendinfo ptr to a structure containing 
                     information how the stuff is to be rendered

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* assemble_header(struct renderinfo* ptr_rendinfo) {
  /* see whether the client specified a character encoding */
  char enc_string[PREFS_BUF_LEN+80];
  char* my_script;
  char* header;
  size_t header_len = 1024;

  if (ptr_rendinfo->javascript == 1) {
    header_len += strlen(checkref_javascript);
    my_script = checkref_javascript;
  }
  else {
    /* ptr to an empty string */
    my_script = &checkref_javascript[strlen(checkref_javascript)];
  }

  if ((header = malloc(header_len)) == NULL) {
    LOG_PRINT(LOG_WARNING, get_status_msg(801));
    return NULL;
  }

  *header = '\0';

  switch (ptr_rendinfo->ref_format) {
  case REFHTML:
    /* fall through */
  case REFXHTML:
    /* html/xhtml output */
    if (*(ptr_rendinfo->ptr_biblio_info->encoding)) {
      if (ptr_rendinfo->ref_format == REFHTML) {
	snprintf(enc_string, PREFS_BUF_LEN+80, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\">\n", ptr_rendinfo->ptr_biblio_info->encoding);
      }
      else { /* XHTML, need to close meta tag for XML */
	snprintf(enc_string, PREFS_BUF_LEN+80, "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=%s\"/>\n", ptr_rendinfo->ptr_biblio_info->encoding);
      }
    }
    else {
      /* should never happen */
      *enc_string = '\0';
    }

    if (*(ptr_rendinfo->cgi_url)) {
      if (ptr_rendinfo->ref_format == REFHTML) {
	snprintf(header, header_len, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n<html>\n<head>\n%s<title>%s reference list</title>\n<meta name=\"generator\" content=\"%s %s\">\n<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n</head>\n<body>\n<h1 class='h1'>refdb reference list</h1>\n", enc_string, PACKAGE, PACKAGE, VERSION, ptr_rendinfo->cgi_url);
      }
      else { /* REFXHTML */
	snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>%s<title>%s reference list</title><meta name=\"generator\" content=\"%s %s\" /><link rel=\"stylesheet\" type=\"text/css\" href=\"%s\" />\n%s</head>\n<body>\n<h1 class='h1'>refdb reference list</h1>\n", ptr_rendinfo->ptr_biblio_info->encoding, enc_string, PACKAGE, PACKAGE, VERSION, ptr_rendinfo->cgi_url, my_script);
      }
    }
    else { /* don't use css */
      if (ptr_rendinfo->ref_format == REFHTML) {
	snprintf(header, header_len, "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\">\n<html>\n<head>\n%s<title>%s reference list</title>\n<meta name=\"generator\" content=\"%s %s\">\n</head>\n<body>\n<h1 class='h1'>refdb reference list</h1>\n", enc_string, PACKAGE, PACKAGE, VERSION);
      }
      else { /* REFXHTML */
	snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\"><head>%s<title>%s reference list</title><meta name=\"generator\" content=\"%s %s\" />%s</head>\n<body>\n<h1 class='h1'>refdb reference list</h1>\n", ptr_rendinfo->ptr_biblio_info->encoding, enc_string, PACKAGE, PACKAGE, VERSION, my_script);
      }
    }
    break;
  case RISX:
    /* risx output */
    if (*(ptr_rendinfo->ptr_clrequest->namespace)) {
      snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", ptr_rendinfo->ptr_biblio_info->encoding);
    }
    else {
      snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n%s", ptr_rendinfo->ptr_biblio_info->encoding, RISX_PUBID);
    }
    break;
  case REFMODS:
    /* MODS output */
    snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", ptr_rendinfo->ptr_biblio_info->encoding);
    break;
  case XNOTE:
    /* xnote output */
    snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n%s", ptr_rendinfo->ptr_biblio_info->encoding, XNOTE_PUBID);
    break;
  case REFCITATIONLISTX:
    /* citationlistx output */
    snprintf(header, header_len, "<?xml version=\"1.0\" encoding=\"%s\"?>\n%s", ptr_rendinfo->ptr_biblio_info->encoding, CITATIONLISTX_PUBID);
    break;
/*   default: */
    /* empty string */
  }


  return header;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  add_root_to_link(): inserts pdfroot into a link. The returned string
                      is malloc()'ed and must be freed by the calling
		      function

  char* add_root_to_link(): returns a malloc()'ed string, or NULL if
                      something goes wrong. One likely reason for the latter
		      is if the link is not relative, or does not use
		      the file:// protocol

  const char* link ptr to string containing the link

  const char* pdfroot ptr to string containing the pdfroot

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* add_root_to_link(const char* link, const char* pdfroot) {
  char* full_link = NULL;

  if (!link || !*link) {
    return NULL;
  }

  if (!pdfroot                           /* no pdfroot available */
      || strlen(link) < 7                /* too short */
      || !strncmp(link, "file:///", 8)   /* not a relative path */
      || strncmp(link, "file://", 7)) {  /* not the appropriate protocol */
    /* return a copy of link */
    if ((full_link = strdup(link)) == NULL) {
      return NULL;
    }
  }
  else {
    /* insert pdfroot after protocol specifier */    
    if ((full_link = malloc(strlen(link)+strlen(pdfroot)+1)) == NULL) {
      return NULL;
    }

    strcpy(full_link, link);

    /* move part after protocol specifier out of the way, including
       the terminating NULL byte */
    memmove(full_link+strlen(pdfroot)+7, full_link+7, strlen(full_link+7)+1);

    /* insert pdfroot into the gap */
    memcpy(full_link+7, pdfroot, strlen(pdfroot));
  }

  return full_link;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  has_part_data(): returns true if a reference type may have part data

  int has_part_data returns 1 if the type has part data, 0 if not

  const char* type ptr to a string containing the reference type to check

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int has_part_data(const char* type) {
  if (!type) {
    return 0;
  }

  if (!strcmp(type, "ABST")
      || !strcmp(type, "CHAP")
      || !strcmp(type, "CASE")
      || !strcmp(type, "CONF")
      || !strcmp(type, "GEN")
      || !strcmp(type, "INPR")
      || !strcmp(type, "UNPB")
      || !strcmp(type, "JOUR")
      || !strcmp(type, "JFULL")
      || !strcmp(type, "MGZN")
      || !strcmp(type, "NEWS")
      || !strcmp(type, "SER")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  has_set_data(): returns true if a reference type may have set data

  int has_set_data returns 1 if the type has set data, 0 if not

  const char* type ptr to a string containing the reference type to check

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int has_set_data(const char* type) {
  if (!type) {
    return 0;
  }

  if (!strcmp(type, "BOOK")
      || !strcmp(type, "CHAP")
      || !strcmp(type, "CONF")
      || !strcmp(type, "DATA")
      || !strcmp(type, "GEN")
      || !strcmp(type, "MPCT")
      || !strcmp(type, "MUSIC")
      || !strcmp(type, "REPORT")
      || !strcmp(type, "SER")
      || !strcmp(type, "SOUND")
      || !strcmp(type, "VIDEO")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  has_periodical_data(): returns true if a reference type has periodical
                         data

  int has_periodical_data returns 1 if the type has periodical data, 0 if not

  const char* type ptr to a string containing the reference type to check

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int has_periodical_data(const char* type) {
  if (!type) {
    return 0;
  }

  if (!strcmp(type, "ABST")
      || !strcmp(type, "CONF")
      || !strcmp(type, "GEN")
      || !strcmp(type, "INPR")
      || !strcmp(type, "UNPB")
      || !strcmp(type, "JOUR")
      || !strcmp(type, "JFULL")
      || !strcmp(type, "MGZN")
      || !strcmp(type, "NEWS")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  has_chapter_data(): returns true if a reference type has something
                      similar to chapter data

  int has_chapter_data returns 1 if the type has periodical data, 0 if not

  const char* type ptr to a string containing the reference type to check

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int has_chapter_data(const char* type) {
  if (!type) {
    return 0;
  }

  if (!strcmp(type, "CASE")
      || !strcmp(type, "CHAP")
      || !strcmp(type, "CONF")
      || !strcmp(type, "GEN")) {
    return 1;
  }
  else {
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_reference_count(): retrieves the number of references in a database

  unsigned long long get_reference_count returns the number of references
                     in the current database, and places the highest ID
                     in the provided counter

  dbi_conn conn database connection

  unsigned long long* ptr_max_id will be set to the highest reference ID 
                     if non-NULL

  int n_istemp if 1, use temporary tables as data source

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned long long get_reference_count(dbi_conn conn, unsigned long long* ptr_max_id, int n_istemp) {
  unsigned long long numrefs;
  char sql_command[128];
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  dbi_result dbires;

  /* fix the insert */
  if (!n_istemp) {
    *prefix = '\0';
  }

  /* SQL functions must be aliased for the sqlite/sqlite3 column type
     magic to work */
  sprintf(sql_command, "SELECT COUNT(*) AS CNT, MAX(refdb_id) AS MX FROM t_%srefdb WHERE refdb_type!='DUMMY'", prefix);

  LOG_PRINT(LOG_DEBUG, sql_command);

  dbires = dbi_conn_query(conn, sql_command);
  if (!dbires
      || !dbi_result_next_row(dbires)) {
    return 0;
  }
  
  numrefs = my_dbi_result_get_idval_idx(dbires, 1); /* 1-base index */
  if (ptr_max_id) {
    *ptr_max_id = my_dbi_result_get_idval_idx(dbires, 2);
  }

  dbi_result_free(dbires);

  return numrefs;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_notes_count(): retrieves the number of notes in a database

  unsigned long long get_notes_count returns the number of notes
                     in the current database, and places the highest ID
                     in the provided counter

  dbi_conn conn database connection

  unsigned long long* ptr_max_id will be set to the highest note ID 
                     if non-NULL

  int n_istemp if 1, use temporary tables as data source

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned long long get_notes_count(dbi_conn conn, unsigned long long* ptr_max_id, int n_istemp) {
  unsigned long long numnotes;
  char sql_command[128];
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  dbi_result dbires;

  /* fix the insert */
  if (!n_istemp) {
    *prefix = '\0';
  }

  /* SQL functions must be aliased for the sqlite/sqlite3 column type
     magic to work */
  sprintf(sql_command, "SELECT COUNT(*) AS CNT, MAX(note_id) AS MX FROM t_%snote", prefix);

  LOG_PRINT(LOG_DEBUG, sql_command);

  dbires = dbi_conn_query(conn, sql_command);
  if (!dbires
      || !dbi_result_next_row(dbires)) {
    return 0;
  }
  
  numnotes = my_dbi_result_get_idval_idx(dbires, 1); /* 1-base index */
  if (ptr_max_id) {
    *ptr_max_id = my_dbi_result_get_idval_idx(dbires, 2);
  }

  dbi_result_free(dbires);

  return numnotes;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  calculate_relative_frequency(): calculates a measure of the frequency
                     of a keyword, authorname or whatever 

  int calculate_relative_frequency returns the relative frequency

  unsigned long long frequency the number of occurrences of the item
                     in the database

  unsigned long long refcount the total number of references in the
                     database

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int calculate_relative_frequency(unsigned long long frequency, unsigned long long refcount) {
  if (!frequency || !refcount || refcount == 1) {
    return 0;
  }
  else {
    /* using log stretches the available span more evenly over several
     orders of magnitude. The resulting values are supposed to be
     between 0 (item appears only on one or a few references) to 9
     (item appears in just about every reference) */
    return (int)(10*(log((double)frequency)/log((double)refcount)));
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_id(): retrieves the note_id element from a note query

  char* get_refdb_note_id returns a pointer to a string containing the 
                     note_id element

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* id ptr to string that will receive the id. Must be long
                    enough for the representation of an unsigned
		    long long number

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_note_id(dbi_result dbires, char* id) {
  unsigned long long n_id;
  dbi_error_flag errflag;

  n_id = my_dbi_result_get_idval(dbires, "note_id");
  errflag = my_dbi_conn_error_flag(dbi_result_get_conn(dbires));

  if (n_id == 0 || errflag) { /* all IDs > 0 so this must be an error */
    return NULL;
  }
  else {
    sprintf(id, ULLSPEC, (unsigned long long)n_id);
    return id;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_key(): retrieves the note_key element from a note query

  char* get_refdb_note_key returns a pointer to a string containing the 
                     note_key element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_note_key(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "note_key");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_user_name(): retrieves the user_name element from a note query

  char* get_refdb_note_user_name returns a pointer to a string containing the 
                     user_name element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_note_user_name(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "user_name");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_title_copy(): retrieves the title element from a note query

  char* get_refdb_note_title_copy returns a pointer to a string containing the 
                     note_title element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_note_title_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "note_title");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_content_copy(): retrieves the content element from a note query

  char* get_refdb_note_content_copy returns a pointer to a string containing the 
                     note_content element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_note_content_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "note_content");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_content_type(): retrieves the content_type element
                                 from a note query

  char* get_refdb_content_type returns a pointer to a string containing the 
                     content_type element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_note_content_type(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "note_content_type");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_content_xmllang(): retrieves the content_xmllang element
                                 from a note query

  char* get_refdb_content_xmllang returns a pointer to a string containing the 
                     content_xmllang element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_note_content_xmllang(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "note_content_xmllang");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_date(): retrieves the note_date element from a note query

  char* get_refdb_note_date returns a pointer to a string containing the 
                     note_date element

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* date string that receives the date. Must be >= 256 byte

  int mode 0 = string 1 = notex representation
  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_note_date(dbi_result dbires, char* date, int mode) {
  time_t the_time;

  the_time = dbi_result_get_datetime(dbires, "note_date");

  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires)) == 0) {
    if (the_time) {
      if (!mode) {
	strftime(date, 256, "%a %b %d %Y", gmtime(&the_time));
      }
      else {
	strftime(date, 256, "%Y-%m-%d", gmtime(&the_time));
      }
    }
    else {
      strcpy(date, "nd");
    }
    return date;
  }
  else {
    return NULL; /* have no date */
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_note_share(): retrieves the share attribute
                                 from a note query

  char* get_refdb_note_share returns 1 if public, 0 if private, -1
                          if not set by user

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
short int get_refdb_note_share(dbi_result dbires) {
  short int result;

  result = dbi_result_get_short(dbires, "note_share");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return 0; /* be paranoid in case of an error */
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_notes_by_ref(): requests all notes that are associated to
                          a given reference

  dbi_result request_notes_by_ref returns a pointer to a dbi result structure
                     which contains the notes

  dbi_conn conn the connection

  int mode 1 = reference entry 2 = keyword entry 4 = author entry
           8 = periodical entry

  const char* user name of current user

  int share 1=share by default, 0=hide by default

  int include_lists 0=ignore reference lists 1=include reference lists

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_notes_by_ref(dbi_conn conn, unsigned long long n_id, int mode, const char* user, int share, int include_lists) {
  int nis_first = 1;
  char* sql_command;
  char* sql_chunk;
  const char* drivername;
  char userspec[512];
  char namespec[512];
  dbi_result dbires;
  dbi_driver driver;

  driver = dbi_conn_get_driver(conn);
  drivername = dbi_driver_get_name(driver);

  sql_command = malloc(4096); 

  if (sql_command == NULL) {
    return NULL;
  }

  sql_chunk = malloc(2048); 

  if (sql_chunk == NULL) {
    free(sql_command);
    return NULL;
  }

  *sql_command = '\0';

  /* assemble substring which selects the notes based on the share settings */
  if (share) {
    snprintf(userspec, 512, "(t_user.user_name=\'%s\' OR (t_user.user_name!=\'%s\' AND t_note.note_share!=0))", user, user);
  }
  else {
    snprintf(userspec, 512, "(t_user.user_name=\'%s\' OR (t_user.user_name!=\'%s\' AND t_note.note_share=1))", user, user);
  }

  /* assemble substring which selects the notes based on the note key
     to exclude reference lists */
  if (!include_lists) {
    size_t namelen;

    namelen = strlen(user);
    snprintf(namespec, 512, " AND NOT (%s(t_note.note_key%s1%s %zd)=\'%s\') ", my_dbi_driver_get_cap(driver, "substring"), my_dbi_driver_get_cap(driver, "substring_from"), my_dbi_driver_get_cap(driver, "substring_for"), namelen, user);
  }
  else {
    *namespec = 0;
  }

  if (!strcmp(my_dbi_driver_get_cap(driver, "union"), "t")) {
    if (mode & REFERENCE) {
      sprintf(sql_chunk,
	      "SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_refdb ON t_xnote.xref_id=t_refdb.refdb_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'REFERENCE\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      strcat(sql_command, sql_chunk);
      nis_first = 0;
    }
    
    if (mode & KEYWORD) {
      sprintf(sql_chunk,
	      "SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id INNER JOIN t_keyword ON t_xnote.xref_id=t_keyword.keyword_id INNER JOIN t_xkeyword ON t_xkeyword.keyword_id=t_keyword.keyword_id INNER JOIN t_refdb ON t_xkeyword.xref_id=t_refdb.refdb_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'KEYWORD\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);

      if (!nis_first) {
	strcat(sql_command, " UNION ");
      }
      strcat(sql_command, sql_chunk);
      nis_first = 0;
    }      

    if (mode & AUTHOR) {
      sprintf(sql_chunk,
	      "SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id INNER JOIN t_author ON t_xnote.xref_id=t_author.author_id INNER JOIN t_xauthor ON t_xauthor.author_id=t_author.author_id INNER JOIN t_refdb ON t_xauthor.refdb_id=t_refdb.refdb_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'AUTHOR\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      if (!nis_first) {
	strcat(sql_command, " UNION ");
      }
      strcat(sql_command, sql_chunk);
      nis_first = 0;
    }      

    if (mode & PERIODICAL) {
      sprintf(sql_chunk,
	      "SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_periodical ON t_xnote.xref_id=t_periodical.periodical_id INNER JOIN t_refdb ON t_refdb.refdb_periodical_id=t_periodical.periodical_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'PERIODICAL\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      if (!nis_first) {
	strcat(sql_command, " UNION ");
      }
      strcat(sql_command, sql_chunk);
    }
  }
  else {
    /* if the db engine does not support UNION, emulate UNION with
       SELECT INTO temptable */
    if (!strcmp(drivername, "mysql")) {
      /* mysql */
      strcpy(sql_command, "CREATE TEMPORARY TABLE t_noteunion \
                                    (note_id BIGINT, \
                                    note_key VARCHAR(255), \
                                    note_title VARCHAR(255), \
                                    note_content BLOB, \
                                    note_content_type VARCHAR(255), \
                                    note_content_xmllang VARCHAR(255), \
                                    note_user_id BIGINT, \
                                    note_date DATETIME)");
    }
    else if (!strcmp(drivername, "pgsql")) {
      /* pgsql */
      strcpy(sql_command, "CREATE TEMPORARY TABLE t_noteunion \
                                   (note_id BIGSERIAL, \
                                    note_key VARCHAR(255) UNIQUE, \
                                    note_title VARCHAR(255), \
                                    note_content TEXT, \
                                    note_content_type VARCHAR(255), \
                                    note_content_xmllang VARCHAR(255), \
                                    note_user_id BIGINT, \
                                    note_date DATE)");
    }
    else if (!strcmp(drivername, "sqlite")) {
      /* sqlite */
      strcpy(sql_command, "CREATE TEMPORARY TABLE t_noteunion \
                                   (note_id INTEGER, \
                                    note_key TEXT, \
                                    note_title TEXT, \
                                    note_content_type TEXT, \
                                    note_content_xmllang TEXT, \
                                    note_user_id INTEGER, \
                                    note_date DATE, \
                                    note_content TEXT)");
    }
    else if (!strcmp(drivername, "sqlite3")) {
      /* sqlite3 */
      strcpy(sql_command, "CREATE TEMPORARY TABLE t_noteunion \
                                   (note_id BIGINT, \
                                    note_key TEXT, \
                                    note_title TEXT, \
                                    note_content_type TEXT, \
                                    note_content_xmllang TEXT, \
                                    note_user_id BIGINT, \
                                    note_date DATE, \
                                    note_content TEXT)");
    }
    /* else: will be caught earlier */

    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires = dbi_conn_query(conn, sql_command);

    if (!dbires) {
      LOG_PRINT(LOG_WARNING, "create temporary table failed");
      free(sql_command);
      free(sql_chunk);
      return NULL;
    }


    /* now collect the data in the temporary table */
    if (mode & REFERENCE) {
      sprintf(sql_chunk,
	      "INSERT INTO t_noteunion (note_id, note_key, note_title, note_user_id, note_date, note_content, note_content_type, note_content_xmllang) SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id INNER JOIN t_refdb ON t_xnote.xref_id=t_refdb.refdb_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'REFERENCE\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      LOG_PRINT(LOG_DEBUG, sql_chunk);
      dbires = dbi_conn_query(conn, sql_chunk);

      if (!dbires) {
	LOG_PRINT(LOG_WARNING, "insert into temporary table failed");
/* 	free(sql_command); */
/* 	free(sql_chunk); */
/* 	return NULL; */
      }
    }
    
    if (mode & KEYWORD) {
      sprintf(sql_chunk,
	      "INSERT INTO t_noteunion (note_id, note_key, note_title, note_user_id, note_date, note_content, note_content_type, note_content_xmllang) SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id INNER JOIN t_keyword ON t_xnote.xref_id=t_keyword.keyword_id INNER JOIN t_xkeyword ON t_xkeyword.keyword_id=t_keyword.keyword_id INNER JOIN t_refdb ON t_xkeyword.xref_id=t_refdb.refdb_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'KEYWORD\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);

      LOG_PRINT(LOG_DEBUG, sql_chunk);
      dbires = dbi_conn_query(conn, sql_chunk);

      if (!dbires) {
	LOG_PRINT(LOG_WARNING, "insert into temporary table failed");
/* 	free(sql_command); */
/* 	free(sql_chunk); */
/* 	return NULL; */
      }
    }      

    if (mode & AUTHOR) {
      sprintf(sql_chunk,
	      "INSERT INTO t_noteunion (note_id, note_key, note_title, note_user_id, note_date, note_content, note_content_type, note_content_xmllang) SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_author ON t_xnote.xref_id=t_author.author_id INNER JOIN t_xauthor ON t_xauthor.author_id=t_author.author_id INNER JOIN t_refdb ON t_xauthor.refdb_id=t_refdb.refdb_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'AUTHOR\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      LOG_PRINT(LOG_DEBUG, sql_chunk);
      dbires = dbi_conn_query(conn, sql_chunk);

      if (!dbires) {
	LOG_PRINT(LOG_WARNING, "insert into temporary table failed");
/* 	free(sql_command); */
/* 	free(sql_chunk); */
/* 	return NULL; */
      }
    }      

    if (mode & PERIODICAL) {
      sprintf(sql_chunk,
	      "INSERT INTO t_noteunion (note_id, note_key, note_title, note_user_id, note_date, note_content, note_content_type, note_content_xmllang) SELECT DISTINCT t_note.note_id, t_note.note_key, t_note.note_title, t_note.note_user_id, t_note.note_date, t_note.note_content, t_note.note_content_type, t_note.note_content_xmllang FROM t_note INNER JOIN t_xnote ON t_note.note_id=t_xnote.note_id INNER JOIN t_periodical ON t_xnote.xref_id=t_periodical.periodical_id INNER JOIN t_refdb ON t_refdb.refdb_periodical_id=t_periodical.periodical_id INNER JOIN t_user ON t_note.note_user_id=t_user.user_id WHERE %s AND t_refdb.refdb_id="ULLSPEC" AND t_xnote.xnote_type=\'PERIODICAL\'%s",
	      userspec,
	      (unsigned long long)n_id,
	      namespec);
      
      LOG_PRINT(LOG_DEBUG, sql_chunk);
      dbires = dbi_conn_query(conn, sql_chunk);

      if (!dbires) {
	LOG_PRINT(LOG_WARNING, "insert into temporary table failed");
/* 	free(sql_command); */
/* 	free(sql_chunk); */
/* 	return NULL; */
      }
    }

    /* now retrieve the datasets again */
    sprintf(sql_command, "SELECT DISTINCT note_id, note_key, note_title, note_user_id, note_date, note_content, note_content_type, note_content_xmllang FROM t_noteunion");

  }

  free(sql_chunk);
	 
  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires = dbi_conn_query(conn, sql_command);

 /*  if (!dbires) { */
    /* begin weird hack */
/*     sprintf(sql_command, "SELECT refdb_id FROM t_refdb where refdb_id=-1"); */
/*     LOG_PRINT(LOG_DEBUG, sql_command); */
/*     dbires = dbi_conn_query(conn, sql_command); */
    /* end weird hack */
/*     return NULL; */
/*   } */

  free(sql_command);

  return dbires;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  free_request_notes_by_ref(): cleans up the resources used by a previous
                               call to request_notes_by_ref

  int free_request_notes_by_ref returns 0 on success and 1 if an error
                               occurs

  dbi_conn conn the connection

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int free_request_notes_by_ref(dbi_conn conn) {
  dbi_result dbires;
  char sql_command[23];

  /* check whether we used a temporary table. If yes, drop it */
  if (strcmp(my_dbi_driver_get_cap(dbi_conn_get_driver(conn), "union"), "t")) {
    /* get rid of the temporary table */
    strcpy(sql_command, "DROP TABLE t_noteunion");
    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires = dbi_conn_query(conn, sql_command);
    
    if (!dbires) {
      LOG_PRINT(LOG_WARNING, "drop temporary table failed");
      return 1;
    }
  }

  return 0;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_links(): prepares the retrieval of links

  dbi_result request_links returns a pointer to a dbi result structure
                     which contains the links

  dbi_conn conn the connection

  int mode 0 = reference entry 1 = keyword entry 2 = author entry
           3 = periodical entry

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_links(dbi_conn conn, unsigned long long n_id, int mode) {
  char* sql_command;
  char linktype[4][11] = {"REFERENCE", "KEYWORD", "AUTHOR", "PERIODICAL"};
  dbi_result dbires;

  sql_command = malloc(512); 

  if (sql_command == NULL) {
    return NULL;
  }

  if (!mode) {
    /* link to refererence. Need citation key */
    sprintf(sql_command, "SELECT t_refdb.refdb_citekey FROM t_refdb INNER JOIN t_xnote ON t_refdb.refdb_id=t_xnote.xref_id INNER JOIN t_note ON t_xnote.note_id= t_note.note_id WHERE t_xnote.xnote_type='\%s\' AND t_note.note_id="ULLSPEC, linktype[mode], (unsigned long long)n_id);
  }
  else if (mode == 1) {
    /* link to keyword. Need keyword name */
    sprintf(sql_command, "SELECT t_keyword.keyword_name FROM t_keyword INNER JOIN t_xnote ON t_keyword.keyword_id=t_xnote.xref_id INNER JOIN t_note ON t_xnote.note_id= t_note.note_id WHERE t_xnote.xnote_type='\%s\' AND t_note.note_id="ULLSPEC, linktype[mode], (unsigned long long)n_id);
  }
  else if (mode == 2) {
    /* link to author. Need author name */
    sprintf(sql_command, "SELECT t_author.author_name FROM t_author INNER JOIN t_xnote ON t_author.author_id=t_xnote.xref_id INNER JOIN t_note ON t_xnote.note_id= t_note.note_id WHERE t_xnote.xnote_type='\%s\' AND t_note.note_id="ULLSPEC, linktype[mode], (unsigned long long)n_id);
  }
  else /* if (mode == 3) */ {
    /* link to periodical. Need one of the periodical names */
    sprintf(sql_command, "SELECT t_periodical.periodical_name,t_periodical.periodical_abbrev,t_periodical.periodical_custabbrev1,t_periodical.periodical_custabbrev2 FROM t_periodical INNER JOIN t_xnote ON t_periodical.periodical_id=t_xnote.xref_id INNER JOIN t_note ON t_xnote.note_id=t_note.note_id WHERE t_xnote.xnote_type='\%s\' AND t_note.note_id="ULLSPEC, linktype[mode], (unsigned long long)n_id);
  }

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires = dbi_conn_query(conn, sql_command);
  free(sql_command);
  if (!dbires) {
    return NULL;
  }

  return dbires;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_link(): retrieves a link

  char* get_link returns a pointer to a string containing the 
                     link

  dbi_result dbires database query result, pointing to the current
                    dataset

  int *ptr_mode pointer to an integer to request the link type. This
                    argument is currently ignored for all but periodical
		    links. Initialize *ptr_mode to one of: 0 = reference entry
		    1 = keyword entry 2 = author entry 3 = periodical entry
		    For successfully retrieved periodical entries,
		    *ptr_mode will be updated to reflect the type of the
		    periodical name used: 0 = full name, 1 = abbreviated
		    name, 2 = custom abbreviation 1, 3 = custom abbreviation 2

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_link(dbi_result dbires, int *ptr_mode) {
  const char* result = NULL;
  int i = 1; /* index into a dbi result, starts at 1 */

  if (dbi_result_next_row(dbires)) {
    if (*ptr_mode == 3) {
      /* periodical links require special treatment as we don't know
	 in advance which periodical names are available */
      while (i < 5 && (!result || !*result)) {
	result = dbi_result_get_string_idx(dbires, i);
	if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	  return NULL;
	}
	else if (result && *result) {
	  *ptr_mode = i-1;
	  return result;
	}
	i++;
      }
      return NULL;
    }
    else {
      result = dbi_result_get_string_idx(dbires, 1);
      if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	return NULL;
      }
      else {
	return result;
      }
    }
  }
  else {
    return NULL;
  }
}

  /* 0  refdb_id             ID  - (if numeric)
     1  refdb_type           TY  - 
     2  refdb_pubyear        PY  - (partial)
     3  refdb_startpage      SP  - 
     4  refdb_endpage        EP  - 
     5  refdb_abstract       N2  - 
     6  refdb_title          TI  - 
     7  refdb_volume         VL  - 
     8  refdb_issue          CP  - 
     9  refdb_booktitle      BT  - 
    10  refdb_city           CY  - 
    11  refdb_publisher      PB  - 
    12  refdb_title_series   T3  - 
    13  refdb_address        AD  - 
    14  refdb_url            UR  - 
    15  refdb_issn           SN  - 
    16  refdb_periodical_id  JO  - (indirect)
    17  refdb_pyother_info   PY  - (partial)
    18  refdb_secyear        Y2  - (partial)
    19  refdb_secother_info  Y2  - (partial)
    20  refdb_user1          U1  - 
    21  refdb_user2          U2  - 
    22  refdb_user3          U3  - 
    23  refdb_user4          U4  - 
    24  refdb_user5          U5  - 
    28  refdb_citekey        ID  - (if non-numeric)
*/

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_id(): retrieves the refdb_id element from a query result

  char* get_refdb_id returns a pointer to a string containing the 
                     refdb_id element

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* id ptr to string that will receive the id. Must be long
                    enough for the representation of an unsigned
		    long long number

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_id(dbi_result dbires, char* id) {
  unsigned long long n_id;
  dbi_error_flag errflag;

  n_id = my_dbi_result_get_idval(dbires, "refdb_id");
  errflag = my_dbi_conn_error_flag(dbi_result_get_conn(dbires));

  if (n_id == 0 || errflag) { /* all IDs > 0 so this must be an error */
    return NULL;
  }
  else {
    sprintf(id, ULLSPEC, (unsigned long long)n_id);
    return id;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_citekey(): retrieves the refdb_citekey element from a query result

  char* get_refdb_citekey returns a pointer to a string containing the 
                     refdb_citekey element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_citekey(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_citekey");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_type(): retrieves the refdb_type element from a query result

  char* get_refdb_type returns a pointer to a string containing the 
                     refdb_type element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_type(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_type");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_pubyear(): retrieves the refdb_pubyear element from a query result

  char* get_refdb_pubyear returns a pointer to a string containing the 
                     refdb_pubyear element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_pubyear(dbi_result dbires, char* year) {
  int n_year;

  n_year = dbi_result_get_short(dbires, "refdb_pubyear");

  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires)) == 0) {
    if (n_year != 0) {
      sprintf(year, "%hd", n_year);
    }
    else {
      strcpy(year, "nd");
    }
    return year;
  }
  else {
    return NULL; /* have no year */
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_startpage(): retrieves the refdb_startpage element from a query result

  char* get_refdb_startpage returns a pointer to a string containing the 
                     refdb_startpage element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_startpage(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_startpage");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_endpage(): retrieves the refdb_endpage element from a query result

  char* get_refdb_endpage returns a pointer to a string containing the 
                     refdb_endpage element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_endpage(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_endpage");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_abstract_copy(): retrieves the refdb_abstract element from
                             a query result

  char* get_refdb_abstract_copy returns a pointer to a string containing the 
                     refdb_abstract element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_abstract_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "refdb_abstract");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_title_copy(): retrieves the refdb_title element from a query result

  char* get_refdb_title_copy returns a pointer to a string containing the 
                     refdb_title element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_title_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "refdb_title");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_volume(): retrieves the refdb_volume element from a query result

  char* get_refdb_volume returns a pointer to a string containing the 
                     refdb_volume element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_volume(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_volume");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_issue(): retrieves the refdb_issue element from a query result

  char* get_refdb_issue  returns a pointer to a string containing the 
                     refdb_issue element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_issue(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_issue");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_booktitle_copy(): retrieves the refdb_booktitle element from a query result

  char* get_refdb_booktitle_copy returns a pointer to a string containing the 
                     refdb_booktitle element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_booktitle_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "refdb_booktitle");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_city(): retrieves the refdb_city element from a query result

  char* get_refdb_city returns a pointer to a string containing the 
                     refdb_city element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_city(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_city");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_publisher(): retrieves the refdb_publisher element from a query result

  char* get_refdb_publisher returns a pointer to a string containing the 
                     refdb_publisher element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_publisher(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_publisher");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_title_series_copy(): retrieves the refdb_title_series
                                 element from a query result

  char* get_refdb_title_series_copy returns a pointer to a string
                     containing the refdb_title_series element. 
                     The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_title_series_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "refdb_title_series");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_address_copy(): retrieves the refdb_address element from a
                            query result

  char* get_refdb_address_copy returns a pointer to a string containing the 
                     refdb_address element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_address_copy(dbi_result dbires) {
  return my_dbi_result_get_string_copy(dbires, "refdb_address");
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_url_copy(): retrieves the refdb_url element from a query result

  char* get_refdb_url_copy returns a pointer to a string containing the 
                     refdb_url element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
/* char* get_refdb_url_copy(dbi_result dbires) { */
/*   return my_dbi_result_get_string_copy(dbires, "refdb_url"); */
/* } */

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_issn(): retrieves the refdb_issn element from a query result

  char* get_refdb_issn returns a pointer to a string containing the 
                     refdb_issn element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_issn(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_issn");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_pyother_info(): retrieves the refdb_pyother_info element from a query result

  char* get_refdb_pyother_info returns a pointer to a string containing the 
                     refdb_pyother_info element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_pyother_info(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_pyother_info");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_secyear(): retrieves the refdb_secyear element from a query result

  char* get_refdb_secyear returns a pointer to a string containing the 
                     refdb_secyear element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_refdb_secyear(dbi_result dbires, char* year) {
  int n_year;

  n_year = dbi_result_get_short(dbires, "refdb_secyear");

  if (n_year != 0 && my_dbi_conn_error_flag(dbi_result_get_conn(dbires)) == 0) {
    sprintf(year, "%hd", n_year);
    return year;
  }
  else {
    return NULL; /* have no year */
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_secother_info(): retrieves the refdb_secother_info element from a query result

  char* get_refdb_secother_info returns a pointer to a string containing the 
                     refdb_secother_info element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_secother_info(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_secother_info");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user(): retrieves refdb_user elements from a query result

  char* get_refdb_user returns a pointer to a string containing the 
                     refdb_user element

  dbi_result dbires database query result, pointing to the current
                    dataset

  int n_fieldno  number of user field to retrieve (1-5)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user(dbi_result dbires, int n_fieldno) {
  switch(n_fieldno) {
  case 1:
    return get_refdb_user1(dbires);
    break;
  case 2:
    return get_refdb_user2(dbires);
    break;
  case 3:
    return get_refdb_user3(dbires);
    break;
  case 4:
    return get_refdb_user4(dbires);
    break;
  case 5:
    return get_refdb_user5(dbires);
    break;
  default:
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user1(): retrieves the refdb_user1 element from a query result

  char* get_refdb_user1 returns a pointer to a string containing the 
                     refdb_user1 element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user1(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_user1");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user2(): retrieves the refdb_user2 element from a query result

  char* get_refdb_user1 returns a pointer to a string containing the 
                     refdb_user2 element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user2(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_user2");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user3(): retrieves the refdb_user3 element from a query result

  char* get_refdb_user3 returns a pointer to a string containing the 
                     refdb_user3 element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user3(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_user3");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user4(): retrieves the refdb_user4 element from a query result

  char* get_refdb_user4 returns a pointer to a string containing the 
                     refdb_user1 element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user4(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_user4");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_user5(): retrieves the refdb_user5 element from a query result

  char* get_refdb_user5 returns a pointer to a string containing the 
                     refdb_user5 element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_user5(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_user5");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_typeofwork(): retrieves the refdb_typeofwork element from a query result

  char* get_refdb_typeofwork returns a pointer to a string containing the 
                     refdb_typeofwork element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_typeofwork(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_typeofwork");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_area(): retrieves the refdb_area element from a query result

  char* get_refdb_area returns a pointer to a string containing the 
                     refdb_area element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_area(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_area");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_ostype(): retrieves the refdb_ostype element from a query result

  char* get_refdb_ostype returns a pointer to a string containing the 
                     refdb_ostype element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_ostype(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_ostype");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_degree(): retrieves the refdb_degree element from a query result

  char* get_refdb_degree returns a pointer to a string containing the 
                     refdb_degree element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_degree(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_degree");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_runningtime(): retrieves the refdb_runningtime element from a query result

  char* get_refdb_runningtime returns a pointer to a string containing the 
                     refdb_runningtime element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_runningtime(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_runningtime");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_classcodeintl(): retrieves the refdb_classcodeintl element
                             from a query result

  char* get_refdb_classcodeintl returns a pointer to a string containing the 
                     refdb_classcodeintl element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_classcodeintl(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_classcodeintl");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_classcodeus(): retrieves the refdb_classcodeus element from
                           a query result

  char* get_refdb_classcodeus returns a pointer to a string containing the 
                     refdb_classcodeus element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_classcodeus(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_classcodeus");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_senderemail(): retrieves the refdb_senderemail element
                           from a query result

  char* get_refdb_senderemail returns a pointer to a string containing the 
                     refdb_senderemail element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_senderemail(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_senderemail");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_recipientemail(): retrieves the refdb_recipientemail element
                              from a query result

  char* get_refdb_recipientemail returns a pointer to a string containing the 
                     refdb_recipientemail element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_recipientemail(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_recipientemail");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_mediatype(): retrieves the refdb_mediatype element from a
                         query result

  char* get_refdb_mediatype returns a pointer to a string containing the 
                     refdb_mediatype element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_mediatype(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_mediatype");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_numvolumes(): retrieves the refdb_numvolumes element from
                          a query result

  char* get_refdb_numvolumes returns a pointer to a string containing the 
                     refdb_numvolumes element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_numvolumes(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_numvolumes");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_doi(): retrieves the refdb_doi element from a query result

  char* get_refdb_doi returns a pointer to a string containing the 
                     refdb_doi element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_doi(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_doi");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_edition(): retrieves the refdb_edition element from a query result

  char* get_refdb_edition returns a pointer to a string containing the 
                     refdb_edition element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_edition(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_edition");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_computer(): retrieves the refdb_computer element from a query result

  char* get_refdb_computer returns a pointer to a string containing the 
                     refdb_computer element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_computer(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_computer");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_conferencelocation(): retrieves the refdb_conferencelocation
                                  element from a query result

  char* get_refdb_conferencelocation returns a pointer to a string
                     containing the 
                     refdb_conferencelocation element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_conferencelocation(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_conferencelocation");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_registrynum(): retrieves the refdb_registrynum element
                           from a query result

  char* get_refdb_registrynum returns a pointer to a string containing the 
                     refdb_registrynum element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_registrynum(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_registrynum");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_classification(): retrieves the refdb_classification element
                              from a query result

  char* get_refdb_classification returns a pointer to a string containing the 
                     refdb_classification element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_classification(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_classification");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_section(): retrieves the refdb_section element from a query result

  char* get_refdb_section returns a pointer to a string containing the 
                     refdb_section element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_section(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_section");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_pamphletnum(): retrieves the refdb_pamphletnum element from a query result

  char* get_refdb_pamphletnum returns a pointer to a string containing the 
                     refdb_ element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_pamphletnum(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_pamphletnum");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_refdb_chapternum(): retrieves the refdb_chapternum element from a query result

  char* get_refdb_chapternum returns a pointer to a string containing the 
                     refdb_ element

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_refdb_chapternum(dbi_result dbires) {
  const char* result;

  result = dbi_result_get_string(dbires, "refdb_chapternum");
  if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
    return NULL;
  }
  else {
    return result;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_notes_copy(): retrieves the xuser_notes element from a query result

  char* get_notes_copy returns a pointer to a string containing the 
                     xuser_notes element. The string is allocated and
		     must be freed by the caller

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* username ptr to string with the current username, or NULL if
                    the search should not be restricted to the 
                    current user

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_notes_copy(dbi_result dbires, char* username) {
  char* sql_command;
  const char* notes = NULL;
  unsigned long long n_id;
  dbi_result dbires1;

  n_id = my_dbi_result_get_idval(dbires, "refdb_id");
  if (n_id == 0) { /* all IDs >=1 so this must be an error */
    return NULL;
  }

  sql_command = malloc(256); 

  if (sql_command == NULL) {
    return NULL;
  }

  if (username != NULL) {
    sprintf(sql_command, "SELECT t_xuser.xuser_notes FROM t_xuser INNER JOIN t_user ON t_xuser.user_id=t_user.user_id WHERE t_user.user_name=\'%s\' AND t_xuser.refdb_id="ULLSPEC, username, (unsigned long long)n_id);
  }
  else { /* use the first entry regardless of which user */
    sprintf(sql_command, "SELECT t_xuser.xuser_notes FROM t_xuser INNER JOIN t_user ON t_xuser.user_id=t_user.user_id WHERE t_xuser.refdb_id="ULLSPEC, (unsigned long long)n_id);
  }

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
  free(sql_command);
  
  if (!dbires1) {
    return NULL;
  }

  if (dbi_result_next_row(dbires1)) {
    /* the result string will be an allocated copy that we have to free */
    notes = my_dbi_result_get_string_copy(dbires1, "xuser_notes");
  }
  dbi_result_free(dbires1);

  /* notes will still be NULL if result contains zero rows */
  return (char*)notes;
}


/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_reprint(): retrieves the xuser_reprint element and related
                 elements from a query result

  struct REPRINT get_reprint returns a structure which points to
                     strings containing the xuser_reprint and
                     xuser_date elements. If the previous search
                     with request_reprint() was limited to the current
                     user, this function will return the reprint status
                     of this user. Otherwise it will search for the
                     first user that has the reference in file. If no
                     one has it in file, it will search for the first
                     user that has it on request. If there is still
                     no match, it will return any "NOT IN FILE" field.
		     In case of an error, one or both REPRINT structure
                     members are NULL

  dbi_result dbires database query result, pointing to the current
                    dataset

  struct REPRINT* ptr_reprint ptr to structure which will receive the result

  char* username ptr to string with username or NULL if search should not
                 be limited to a particular user

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
struct REPRINT* get_reprint(dbi_result dbires, struct REPRINT* ptr_reprint, char* username, int yeardigits) {
  char* sql_command;
  const char* xuser_reprint;
  const char* xuser_avail;
  int num_rows;
  unsigned long long n_id;
  time_t reprint_date;
  dbi_conn conn;
  dbi_result dbires1;

  sql_command = malloc(256); 

  if (sql_command == NULL) {
    return NULL;
  }

  n_id = my_dbi_result_get_idval(dbires, "refdb_id");

  if (n_id == 0) { /* all IDs > 0, so this must be an error */
    free(sql_command);
    return NULL;
  }

  conn = dbi_result_get_conn(dbires);

  if (username != NULL) {
    sprintf(sql_command, "SELECT t_xuser.xuser_reprint, t_xuser.xuser_date, t_xuser.xuser_avail FROM t_xuser INNER JOIN t_user ON t_xuser.user_id=t_user.user_id WHERE t_user.user_name=\'%s\' AND t_xuser.refdb_id="ULLSPEC, username, (unsigned long long)n_id);
  }
  else {
    sprintf(sql_command, "SELECT t_xuser.xuser_reprint, t_xuser.xuser_date, t_xuser.xuser_avail FROM t_xuser WHERE t_xuser.refdb_id="ULLSPEC, (unsigned long long)n_id);
  }

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires1 = dbi_conn_query(conn, sql_command);
  free(sql_command);
  
  if (!dbires1) {
    return NULL;
  }

  /* check how many rows. If > 1, search for first entry IN FILE, or
     ON REQUEST if the former is not found. Assemble string from the
     user_reprint and user_date columns */

  /* set defaults */
  (ptr_reprint->reprint)[0] = '\0';
  (ptr_reprint->date)[0] = '\0';
  (ptr_reprint->avail)[0] = '\0';

  if ((num_rows = dbi_result_get_numrows(dbires1)) > 1) {
    /* find first entry IN FILE */
    while (dbi_result_next_row(dbires1)) {
      xuser_reprint = dbi_result_get_string_idx(dbires1, 1);
      if (!xuser_reprint || my_dbi_conn_error_flag(conn)) {
	continue;
      }
      if (strncmp(xuser_reprint, "IN FILE", 7) == 0) {
	strcpy(ptr_reprint->reprint, xuser_reprint);
	reprint_date = dbi_result_get_datetime_idx(dbires1, 2);
	if (reprint_date && !my_dbi_conn_error_flag(conn)) {
	  print_risdate(&reprint_date, ptr_reprint->date, yeardigits);
	}
	xuser_avail = dbi_result_get_string_idx(dbires1, 3);
	if (xuser_avail && !my_dbi_conn_error_flag(conn)) {
	  strcpy(ptr_reprint->avail, xuser_avail);
	}
	return ptr_reprint; /* the first IN FILE entry */
      }
    } /* end while */

    /* rewind... */
    dbi_result_first_row(dbires1);

    while (dbi_result_next_row(dbires1)) {
      xuser_reprint = dbi_result_get_string_idx(dbires1, 1);
      if (!xuser_reprint || my_dbi_conn_error_flag(conn)) {
	continue;
      }
      if (strncmp(xuser_reprint, "ON REQUEST", 10) == 0) {
	strcpy(ptr_reprint->reprint, xuser_reprint);
	reprint_date = dbi_result_get_datetime_idx(dbires1, 2);
	if (reprint_date && !my_dbi_conn_error_flag(conn)) {
	  print_risdate(&reprint_date, ptr_reprint->date, yeardigits);
	}
	xuser_avail = dbi_result_get_string_idx(dbires1, 3);
	if (xuser_avail && !my_dbi_conn_error_flag(conn)) {
	  strcpy(ptr_reprint->avail, xuser_avail);
	}
	return ptr_reprint; /* the first ON REQUEST entry */
      }
    } /* end while */

    /* rewind... */
    dbi_result_first_row(dbires1);
    
    if (dbi_result_next_row(dbires1)) {
      xuser_reprint = dbi_result_get_string_idx(dbires1, 1);
      if (xuser_reprint && !my_dbi_conn_error_flag(conn)) {
	strcpy(ptr_reprint->reprint, xuser_reprint);
      }
      reprint_date = dbi_result_get_datetime_idx(dbires1, 2);
      if (reprint_date && !my_dbi_conn_error_flag(conn)) {
	print_risdate(&reprint_date, ptr_reprint->date, yeardigits);
      }
      xuser_avail = dbi_result_get_string_idx(dbires1, 3);
      if (xuser_avail && !my_dbi_conn_error_flag(conn)) {
	strcpy(ptr_reprint->avail, xuser_avail);
      }
      return ptr_reprint; /* the first NOT IN FILE entry */
    }
    else {
      return ptr_reprint; /* have nothing */
    }
  }
  else if (num_rows == 1) {
    if (dbi_result_next_row(dbires1)) {
      xuser_reprint = dbi_result_get_string_idx(dbires1, 1);
      if (xuser_reprint && !my_dbi_conn_error_flag(conn)) {
	strcpy(ptr_reprint->reprint, xuser_reprint);
      }
      reprint_date = dbi_result_get_datetime_idx(dbires1, 2);
      if (reprint_date && !my_dbi_conn_error_flag(conn)) {
	print_risdate(&reprint_date, ptr_reprint->date, yeardigits);
      }
      xuser_avail = dbi_result_get_string_idx(dbires1, 3);
      if (xuser_avail && !my_dbi_conn_error_flag(conn)) {
	strcpy(ptr_reprint->avail, xuser_avail);
      }
      return ptr_reprint; /* the first NOT IN FILE entry */
    }
    else {
      return ptr_reprint; /* have nothing */
    }
  }
  else {
    return ptr_reprint; /* have nothing */
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_periodical(): prepares the retrieval of periodical from
                           a given database

  char* get_periodical returns the periodical string or NULL if an
                    error occurred

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* periodical ptr to string that will receive the result. Must
                    hold at least 256 characters.

  const char* db string holding the database to search in, or NULL if the
                  current database should be used

  int type indicates which periodical name is to be retrieved. 0=name, 
                     1=custabbrev1, 2=custabbrev2, 3=abbrev, 4=the first
                     existing name in the order name, abbrev, custabbrev1,
                     custabbrev2

  int* errcode ptr to an int that will receive the error code
               (0 = no error, 1 = nothing found, 2 = memory error,
	        3 = database server error)

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long n_id ID of the dataset

  unsigned long long* ptr_frequency will be set to the frequency of the
                     periodical in the database unless NULL

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* get_periodical(dbi_conn conn, char* periodical, const char* db, int type, int* errcode, int is_temp, unsigned long long n_id, unsigned long long* ptr_frequency) {
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  char *sql_command;
  char *dbstring = NULL;
  const char *item;
  const char *drivername;
  int i;
  dbi_result dbires1;

  /* fix the insert */
  if (!is_temp) {
    *prefix = '\0';
  }

  drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));

  sql_command = malloc(1024); 

  if (sql_command == NULL) {
    *errcode = 2;
    return NULL;
  }

  if (!n_id) {
    *errcode = 1;
    return NULL;
  }

  /* never use db argument with pgsql driver */
  if (db && *db && !strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
    dbstring = malloc(strlen(db)+2); 

    if (dbstring == NULL) {
      *errcode = 2;
      return NULL;
    }
    sprintf(dbstring, "%s.", db);
  }
  else {
    /* this is weird but simplifies the free() calls further down */
    dbstring = malloc(1); 

    if (dbstring == NULL) {
      *errcode = 2;
      return NULL;
    }
    dbstring[0] = '\0';
  }

  if (type == 4) {
    /* we try all periodical names in a fixed order and return the first
       one we can find, or NULL if we don't find anything */
    for (i = 0; i < 4; i++) {
      switch (i) {
      case 0:
	/* first try name */
	sprintf(sql_command, "SELECT %st_%speriodical.periodical_name, %st_%speriodical.periodical_id FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
	break;
      case 1:
	/* then try abbrev */
	sprintf(sql_command, "SELECT %st_%speriodical.periodical_abbrev, %st_%speriodical.periodical_id  FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
	break;
      case 2:
	/* then try custabbrev1 */
	sprintf(sql_command, "SELECT %st_%speriodical.periodical_custabbrev1, %st_%speriodical.periodical_id  FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
	break;
      case 3:
	/* finally try custabbrev2 */
	sprintf(sql_command, "SELECT %st_%speriodical.periodical_custabbrev2, %st_%speriodical.periodical_id  FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
	break;
      default:
	LOG_PRINT(LOG_CRIT, "hope you never see this");
	return NULL;
      }

      LOG_PRINT(LOG_DEBUG, sql_command);
      dbires1 = dbi_conn_query(conn, sql_command);
      if (!dbires1) {
	*errcode = 3;
	free(sql_command);
	free(dbstring);
	return NULL;
      }

      item = real_get_periodical(dbires1, is_temp, ptr_frequency);

      if (item && *item) {
	/* we're done, copy string into provided buffer and return it */
	*errcode = 0;
	strcpy(periodical, item);
	dbi_result_free(dbires1);
	free(sql_command);
	free(dbstring);
	return periodical;
      }
    } /* end for */


    if (i == 4) { /* nothing found */
      *errcode = 1;
      free(sql_command);
      free(dbstring);
      return NULL;
    }
  }
  else {
    if (!type) {
      sprintf(sql_command, "SELECT %st_%speriodical.periodical_name, %st_%speriodical.periodical_id FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
    }
    else if (type == 1) {
      sprintf(sql_command, "SELECT %st_%speriodical.periodical_custabbrev1, %st_%speriodical.periodical_id FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
    }
    else if (type == 2) {
      sprintf(sql_command, "SELECT %st_%speriodical.periodical_custabbrev2, %st_%speriodical.periodical_id FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
    }
    else if (type == 3) {
      sprintf(sql_command, "SELECT %st_%speriodical.periodical_abbrev, %st_%speriodical.periodical_id FROM %st_%speriodical INNER JOIN %st_%srefdb ON %st_%srefdb.refdb_periodical_id=%st_%speriodical.periodical_id WHERE %st_%srefdb.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);
    }

    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires1 = dbi_conn_query(conn, sql_command);
  
    free(sql_command);
    free(dbstring);

    if (!dbires1) {
      *errcode = 3;
      return NULL;
    }

    item = real_get_periodical(dbires1, is_temp, ptr_frequency);
    if (!item) {
      *errcode = 1;
      dbi_result_free(dbires1);
      return NULL;
    }
    else {
      *errcode = 0;
      strcpy(periodical, item);
      dbi_result_free(dbires1);
      return periodical;
    }
  }
  /* we should never arrive here - just to silence the compiler warning */
  return NULL;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  real_get_periodical(): retrieves the periodical from a query result

  char* real_get_periodical returns a pointer to a string containing the 
                     periodical

  dbi_result dbires database query result, pointing to the current
                    dataset

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long* ptr_frequency will be set to the frequency of
                    the periodical in the database unless NULL

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
static const char* real_get_periodical(dbi_result dbires, int is_temp, unsigned long long* ptr_frequency) {
  const char* result;
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  char sql_command[256];
  unsigned long long periodical_id;
  unsigned long long periodical_num;
  dbi_result dbires1;

  /* fix the insert */
  if (is_temp == 0 || is_temp == 2) {
    *prefix = '\0';
  }



  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    if (ptr_frequency) {
      periodical_id = my_dbi_result_get_idval_idx(dbires, 2);
      
      sprintf(sql_command, "SELECT count(*) FROM t_%srefdb WHERE t_%srefdb.refdb_periodical_id="ULLSPEC, prefix, prefix, (unsigned long long)periodical_id);

      LOG_PRINT(LOG_DEBUG, sql_command);

      dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
      if (!dbires1) {
	*ptr_frequency = 0;
	return NULL;
      }

      if (dbi_result_next_row(dbires1)) {
	periodical_num = my_dbi_result_get_idval_idx(dbires1, 1);
	if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	  dbi_result_free(dbires1);
	  *ptr_frequency = 0;
	  return NULL;
	}
	dbi_result_free(dbires1);
	*ptr_frequency = periodical_num;
	return result;
      }
      else {
	dbi_result_free(dbires1);
	*ptr_frequency = 0;
	return NULL;
      }
    }

    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_authors(): prepares the retrieval of authors from the
                     currently selected database

  dbi_result request_authors returns a query result
                     which contains the authors

  dbi_conn conn connection to the database server

  int type 1 = part author, 2 = publication author, 3 = set author,
           4 = first available, 0 = all of them

  const char* role ptr to a string with contributor role, or NULL

  const char* db ptr to a string with the database name or NULL if the
                    current database should be used

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long n_id id of the dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_authors(dbi_conn conn, int type, const char* role, const char* db, int is_temp, unsigned long long n_id) {
  char* sql_command;
  char* dbstring;
  char* type_clause;
  char* role_clause;
  const char* drivername;
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  unsigned long long num_authors = 0;
  int i = 1;
  dbi_result dbires = NULL;
  dbi_driver driver = NULL;

  if (type == 4) {
    /* recursively call ourselves with all possible author types */
    while (i < 4 && !num_authors) {
      dbires = request_authors(conn, i, role, db, is_temp, n_id);
      if (dbires) {
	num_authors = get_num_authors(dbires);
	if (!num_authors && i < 3) {
	  clean_request(dbires);
	}
      }
      i++;
    }
    return dbires;
  }
  else {
    /* fix the insert */
    if (!is_temp) {
      *prefix = '\0';
    }

    /* never use db argument with pgsql */
    if (db && *db && !strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
      dbstring = malloc(strlen(db)+2); 
      
      if (dbstring == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
      sprintf(dbstring, "%s.", db);
    }
    else {
      /* this is weird but simplifies the free() calls further down */
      dbstring = malloc(1); 
      
      if (dbstring == NULL) {
	LOG_PRINT(LOG_CRIT, get_status_msg(801));
	return NULL;
      }
      *dbstring = '\0';
    }

    if ((type_clause = malloc(64+strlen(dbstring)+strlen(prefix))) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(dbstring);
      return NULL;
    }
    else {
      *type_clause = '\0';
    }

    if ((role_clause = malloc(64+strlen(dbstring)+strlen(prefix)+((role) ? strlen(role):0))) == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(dbstring);
      return NULL;
    }
    else {
      *role_clause = '\0';
    }

    if (type != 0) {
      sprintf(type_clause, " %st_%sxauthor.xauthor_type=%s AND ", dbstring, prefix, get_author_type_string(driver, type));
    }

    if (role && *role) {
      sprintf(role_clause, " %st_%sxauthor.xauthor_role=\'%s\' AND ", dbstring, prefix, role);
    }

    driver = dbi_conn_get_driver(conn);
    drivername = dbi_driver_get_name(driver);

    sql_command = malloc(1024); 

    if (sql_command == NULL) {
      LOG_PRINT(LOG_CRIT, get_status_msg(801));
      free(type_clause);
      free(role_clause);
      return NULL;
    }

    sprintf(sql_command, "SELECT %st_%sauthor.author_name,%st_%sauthor.author_lastname,%st_%sauthor.author_firstname,%st_%sauthor.author_middlename,%st_%sauthor.author_suffix,%st_%sxauthor.xauthor_role, %st_%sxauthor.author_id FROM %st_%sauthor INNER JOIN %st_%sxauthor ON %st_%sauthor.author_id=%st_%sxauthor.author_id WHERE %s %s %st_%sxauthor.refdb_id="ULLSPEC" ORDER BY t_%sxauthor.xauthor_position", dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, type_clause, role_clause, dbstring, prefix, (unsigned long long)n_id, prefix);

    LOG_PRINT(LOG_DEBUG, sql_command);
    free(type_clause);
    free(role_clause);

    dbires = dbi_conn_query(conn, sql_command);

    free(sql_command);
    free(dbstring);

    return dbires;
  } /* end if type==4 */
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_num_authors(): retrieves the number of authors

  int get_num_authors returns the number of requested authors

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned long long get_num_authors(dbi_result dbires) {
  return dbi_result_get_numrows(dbires);
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_author(): retrieves an author

  char* get_author returns a pointer to a string containing the 
                     author

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_author(dbi_result dbires) {
  const char* result;

  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_author_parts(): retrieves an author's name parts

  struct AUTHOR_INFO* get_author_parts
                      returns a pointer to a struct containing the 
                      author name parts

  dbi_result dbires database query result, pointing to the current
                    dataset

  struct AUTHOR_INFO* ptr_ainfo ptr to a structure that will receive
                    the result

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
struct AUTHOR_INFO* get_author_parts(dbi_result dbires, struct AUTHOR_INFO* ptr_ainfo) {
  const char* result;

  /* start with a clean struct */
  ptr_ainfo->name[0] = '\0';
  ptr_ainfo->lastname[0] = '\0';
  ptr_ainfo->firstname[0] = '\0';
  ptr_ainfo->middlename[0] = '\0';
  ptr_ainfo->suffix[0] = '\0';
  ptr_ainfo->role[0] = '\0';

  if (dbi_result_next_row(dbires)) {
    /* full name */
    result = dbi_result_get_string_idx(dbires, 1);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->name, result);
    }

    /* last name */
    result = dbi_result_get_string_idx(dbires, 2);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->lastname, result);
    }

    /* first name */
    result = dbi_result_get_string_idx(dbires, 3);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->firstname, result);
    }

    /* middle name */
    result = dbi_result_get_string_idx(dbires, 4);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->middlename, result);
    }

    /* suffix */
    result = dbi_result_get_string_idx(dbires, 5);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->suffix, result);
    }

    /* role */
    result = dbi_result_get_string_idx(dbires, 6);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->role, result);
    }
  }
  else {
    return NULL;
  }

  return ptr_ainfo;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_extended_author(): retrieves an author along with its frequency

  char* get_extended_author returns a pointer to a string containing the 
                     author

  dbi_result dbires database query result, pointing to the current
                    dataset

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long* ptr_frequency ptr to an integer that will be
                    set to the frequency of the author in the database

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_extended_author(dbi_result dbires, int is_temp, unsigned long long* ptr_frequency) {
  const char* result;
  char sql_command[128];
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  unsigned long long author_id;
  unsigned long long author_num;
  dbi_result dbires1;

  /* fix the insert */
  if (is_temp == 0 || is_temp == 2) {
    *prefix = '\0';
  }

  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    author_id = my_dbi_result_get_idval_idx(dbires, 7);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    
    /* retrieve frequency information */
    sprintf(sql_command, "SELECT count(*) FROM t_%sxauthor WHERE author_id="ULLSPEC, prefix, (unsigned long long)author_id);
    
    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
    if (!dbires1) {
      *ptr_frequency = 0;
      return NULL;
    }

    if (dbi_result_next_row(dbires1)) {
      author_num = my_dbi_result_get_idval_idx(dbires1, 1);
      if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	dbi_result_free(dbires1);
	*ptr_frequency = 0;
	return NULL;
      }
      dbi_result_free(dbires1);
      *ptr_frequency = author_num;
      return result;
    }
    else {
      dbi_result_free(dbires1);
      *ptr_frequency = 0;
      return NULL;
    }
  }
  else {
    *ptr_frequency = 0;
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_extended_author_parts(): retrieves an author's name parts including
                               the frequency

  struct AUTHOR_INFO* get_extended_author_parts
                     returns a pointer to a struct containing the 
                     author name parts

  dbi_result dbires database query result, pointing to the current
                    dataset

  struct AUTHOR_INFO* ptr_ainfo ptr to a structure that will receive
                    the result

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long* ptr_frequency ptr to an integer that will be
                    set to the frequency of the author in the database

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
struct AUTHOR_INFO* get_extended_author_parts(dbi_result dbires, struct AUTHOR_INFO* ptr_ainfo, int is_temp, unsigned long long* ptr_frequency) {
  const char* result;
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  char sql_command[128];
  unsigned long long author_id;
  unsigned long long author_num;
  dbi_result dbires1;

  /* fix the insert */
  if (is_temp == 0 || is_temp == 2) {
    *prefix = '\0';
  }

  /* start with a clean struct */
  ptr_ainfo->name[0] = '\0';
  ptr_ainfo->lastname[0] = '\0';
  ptr_ainfo->firstname[0] = '\0';
  ptr_ainfo->middlename[0] = '\0';
  ptr_ainfo->suffix[0] = '\0';
  ptr_ainfo->role[0] = '\0';

  if (dbi_result_next_row(dbires)) {
    /* full name */
    result = dbi_result_get_string_idx(dbires, 1);
    author_id = my_dbi_result_get_idval_idx(dbires, 7);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->name, result);
    }

    /* last name */
    result = dbi_result_get_string_idx(dbires, 2);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->lastname, result);
    }

    /* first name */
    result = dbi_result_get_string_idx(dbires, 3);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->firstname, result);
    }

    /* middle name */
    result = dbi_result_get_string_idx(dbires, 4);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->middlename, result);
    }

    /* suffix */
    result = dbi_result_get_string_idx(dbires, 5);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->suffix, result);
    }

    /* role */
    result = dbi_result_get_string_idx(dbires, 6);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else if (result) {
      strcpy(ptr_ainfo->role, result);
    }
    /* retrieve frequency information */
    sprintf(sql_command, "SELECT count(*) FROM t_%sxauthor WHERE author_id="ULLSPEC, prefix, (unsigned long long)author_id);
    
    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
    if (!dbires1) {
      *ptr_frequency = 0;
      return NULL;
    }

    if (dbi_result_next_row(dbires1)) {
      author_num = my_dbi_result_get_idval_idx(dbires1, 1);
      if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	dbi_result_free(dbires1);
	*ptr_frequency = 0;
	return NULL;
      }
      dbi_result_free(dbires1);
      *ptr_frequency = author_num;
      return ptr_ainfo;
    }
    else {
      dbi_result_free(dbires1);
      *ptr_frequency = 0;
      return NULL;
    }
  }
  else {
    *ptr_frequency = 0;
    return NULL;
  }

  return ptr_ainfo;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_keywords(): prepares the retrieval of keywords

  dbi_result request_keywords returns a pointer to a dbi result structure
                     which contains the keywords

  dbi_result dbires database query result, pointing to the current
                    dataset (used only to retrieve the connection)

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  int is_temp if 1, query temporary table for a dupcheck

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_keywords(dbi_conn conn, unsigned long long n_id, int mode, int is_temp) {
  char* sql_command;
  char keytype[2][10] = {"REFERENCE", "NOTE"};
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  dbi_result dbires;

  sql_command = malloc(512); 

  if (sql_command == NULL) {
    return NULL;
  }

  /* fix the insert */
  if (!is_temp) {
    *prefix = '\0';
  }

  /* NB sorting the keywords is not strictly necessary but it
     simplifies roundtrip addref/getref analyses */
  sprintf(sql_command, "SELECT t_%skeyword.keyword_name, t_%skeyword.keyword_id FROM t_%skeyword INNER JOIN t_%sxkeyword ON t_%skeyword.keyword_id=t_%sxkeyword.keyword_id WHERE t_%sxkeyword.xkeyword_type=\'%s\' AND t_%sxkeyword.xref_id="ULLSPEC" ORDER BY t_%skeyword.keyword_name", prefix, prefix, prefix, prefix, prefix, prefix, prefix, keytype[mode], prefix, (unsigned long long)n_id, prefix);

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires = dbi_conn_query(conn, sql_command);
  free(sql_command);
  if (!dbires) {
    return NULL;
  }

  return dbires;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_keyword(): retrieves a keyword

  char* get_keyword returns a pointer to a string containing the 
                     keyword

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_keyword(dbi_result dbires) {
  const char* result;

  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_extended_keyword(): retrieves a keyword along with its frequency

  char* get_extended_keyword returns a pointer to a string containing the 
                     keyword

  dbi_result dbires database query result, pointing to the current
                    dataset

  int is_temp if 1, query temporary table for a dupcheck
              if 2, query temporary tables, but use frequency in 
                    permanent tables
	      if 0, query permanent tables

  unsigned long long* ptr_frequency ptr to an integer that will be
                    set to the frequency of the keyword in the database

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_extended_keyword(dbi_result dbires, int is_temp, unsigned long long* ptr_frequency) {
  const char* result;
  char sql_command[128];
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  unsigned long long keyword_id;
  unsigned long long keyword_num;
  dbi_result dbires1;

  /* fix the insert */
  if (is_temp == 0 || is_temp == 2) {
    *prefix = '\0';
  }

  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    keyword_id = my_dbi_result_get_idval_idx(dbires, 2);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    
    /* retrieve frequency information */
    sprintf(sql_command, "SELECT count(*) FROM t_%sxkeyword WHERE keyword_id="ULLSPEC, prefix, (unsigned long long)keyword_id);
    
    LOG_PRINT(LOG_DEBUG, sql_command);
    dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
    if (!dbires1) {
      *ptr_frequency = 0;
      return NULL;
    }

    if (dbi_result_next_row(dbires1)) {
      keyword_num = my_dbi_result_get_idval_idx(dbires1, 1);
      if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
	dbi_result_free(dbires1);
	*ptr_frequency = 0;
	return NULL;
      }
      dbi_result_free(dbires1);
      *ptr_frequency = keyword_num;
      return result;
    }
    else {
      dbi_result_free(dbires1);
      *ptr_frequency = 0;
      return NULL;
    }
  }
  else {
    *ptr_frequency = 0;
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_num_keywords(): retrieves the number of keywords

  int get_num_keywords returns the number of requested keywords

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
unsigned long long get_num_keywords(dbi_result dbires) {
  return dbi_result_get_numrows(dbires);
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_ulinks(): prepares the retrieval of ulinks

  dbi_result request_ulinks returns a pointer to a dbi result structure
                     which contains the ulinks

  dbi_result dbires database query result, pointing to the current
                    dataset (used only to retrieve the connection)

  int mode 0 = reference entry 1 = note entry

  int type 0 = URL, 1 = PDF, 2 = FULLTEXT 3 = RELATED 4 = IMAGE 5 = DOI

  int is_temp if 1, query temporary table for a dupcheck
 
  const char* username name of user. If NULL or empty, all links will
                    be retrieved. If given, only the links of that user
                    and all links not associated with a user will
                    be retrieved. The name "NULL" (don't confuse with
		    a NULL pointer) will retrieve only those links that are
		    not owned by a particular user (but then don't
		    allow "NULL" as a username!)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_ulinks(dbi_conn conn, unsigned long long n_id, int mode, int type, int is_temp, const char* username) {
  char* sql_command;
  char keymode[2][10] = {"REFERENCE", "NOTE"};
  char keytype[6][10] = {"URL", "PDF", "FULLTEXT", "RELATED", "IMAGE", "DOI"};
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  dbi_result dbires;

  sql_command = malloc(512); 

  if (sql_command == NULL) {
    return NULL;
  }

  /* fix the insert */
  if (!is_temp) {
    *prefix = '\0';
  }

  if (username && !strcmp(username, "NULL")) {
    /* only those not owned by a particular user */
    sprintf(sql_command, "SELECT DISTINCT t_%slink.link_url FROM t_%slink INNER JOIN t_%sxlink ON t_%slink.link_id=t_%sxlink.link_id WHERE t_%sxlink.xlink_type=\'%s\' AND t_%sxlink.xlink_source=\'%s\' AND t_%sxlink.xref_id="ULLSPEC" AND t_%sxlink.user_id=0" , prefix, prefix, prefix, prefix, prefix, prefix, keytype[type], prefix, keymode[mode], prefix, (unsigned long long)n_id, prefix);
  }
  else if (username && *username) {
    /* those owned by a particular user, and all not owned by one */
    /* NB the order of t_user and t_link in the FROM clause is
       critical in PostgreSQL */
    if (!type || type == 5) { /* URL and DOI are always public */
      sprintf(sql_command, "SELECT DISTINCT t_%slink.link_url FROM t_%suser,t_%slink INNER JOIN t_%sxlink ON t_%slink.link_id=t_%sxlink.link_id WHERE t_%sxlink.xlink_type=\'%s\' AND t_%sxlink.xlink_source=\'%s\' AND t_%sxlink.xref_id="ULLSPEC" AND t_%sxlink.user_id=0" , prefix, prefix, prefix, prefix, prefix, prefix, prefix, keytype[type], prefix, keymode[mode], prefix, (unsigned long long)n_id, prefix);
    }
    else { /* we really mean private */
      sprintf(sql_command, "SELECT DISTINCT t_%slink.link_url FROM t_%suser,t_%slink INNER JOIN t_%sxlink ON t_%slink.link_id=t_%sxlink.link_id WHERE t_%sxlink.xlink_type=\'%s\' AND t_%sxlink.xlink_source=\'%s\' AND t_%sxlink.xref_id="ULLSPEC" AND (t_%sxlink.user_id=t_%suser.user_id AND t_%suser.user_name=\'%s\')" , prefix, prefix, prefix, prefix, prefix, prefix, prefix, keytype[type], prefix, keymode[mode], prefix, (unsigned long long)n_id, prefix, prefix, prefix, username);
    }
  }
  else {
    /* all */
    sprintf(sql_command, "SELECT DISTINCT t_%slink.link_url FROM t_%slink INNER JOIN t_%sxlink ON t_%slink.link_id=t_%sxlink.link_id WHERE t_%sxlink.xlink_type=\'%s\' AND t_%sxlink.xlink_source=\'%s\' AND t_%sxlink.xref_id="ULLSPEC, prefix, prefix, prefix, prefix, prefix, prefix, keytype[type], prefix, keymode[mode], prefix, (unsigned long long)n_id);
  }

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires = dbi_conn_query(conn, sql_command);
  free(sql_command);
  if (!dbires) {
    return NULL;
  }

  return dbires;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_ulink(): retrieves an ulink

  char* get_ulink returns a pointer to a string containing the 
                     ulink

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_ulink(dbi_result dbires) {
  const char* result;

  if (dbi_result_next_row(dbires)) {
    result = my_dbi_result_get_string_idx(dbires, 1);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  request_users(): prepares the retrieval of users of the
                     currently selected database

  dbi_result request_users returns a query result
                     which contains the users

  dbi_conn conn connection to database server

  const char* db ptr to a string with the database name or NULL if the
                    current database should be used

  int is_temp if 1, query temporary table for a dupcheck

  unsigned long long n_id id of the dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result request_users(dbi_conn conn, const char* db, int is_temp, unsigned long long n_id) {
  char prefix[] = TEMP_TABLE_NAME_PREFIX;
  char *sql_command;
  char *dbstring;
  const char *drivername;
  dbi_result dbires;
  dbi_driver driver;

  driver = dbi_conn_get_driver(conn);
  drivername = dbi_driver_get_name(driver);

  sql_command = malloc(1024); 

  if (sql_command == NULL) {
    return NULL;
  }

  /* fix the insert */
  if (!is_temp) {
    *prefix = '\0';
  }

  /* never use db argument with pgsql */
  if (db && *db && !strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
    dbstring = malloc(strlen(db)+2); 

    if (dbstring == NULL) {
      return NULL;
    }
    sprintf(dbstring, "%s.", db);
  }
  else {
    /* this is weird but simplifies the free() calls further down */
    dbstring = malloc(1); 

    if (dbstring == NULL) {
      return NULL;
    }
    dbstring[0] = '\0';
  }

  sprintf(sql_command, "SELECT %st_%suser.user_name FROM %st_%suser INNER JOIN %st_%sxuser ON %st_%suser.user_id=%st_%sxuser.user_id WHERE %st_%sxuser.refdb_id="ULLSPEC, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, dbstring, prefix, (unsigned long long)n_id);

  LOG_PRINT(LOG_DEBUG, sql_command);

  dbires = dbi_conn_query(conn, sql_command);
  free(sql_command);
  free(dbstring);

  return dbires;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_user(): retrieves an user

  char* get_user returns a pointer to a string containing the 
                     user

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_user(dbi_result dbires) {
  const char* result;

  if (dbi_result_next_row(dbires)) {
    result = dbi_result_get_string_idx(dbires, 1);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  clean_request() frees the dbi result data structure after a request is
                  finished

  void clean_request

  dbi_result dbires database query result, pointing to the current
                    dataset

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void clean_request(dbi_result dbires) {
  dbi_result_free(dbires);
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  my_dbi_result_get_string_copy(): retrieves a given field which is either a
                            string or a binary string from a query result

  char* my_dbi_result_get_string_copy returns a pointer to a string containing the 
                     requested field element, or NULL in case something
		     went wrong. The returned string must be freed by the
		     calling function

  dbi_result dbires database query result, pointing to the current
                    dataset

  const char* fieldname name of the field to retrieve

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* my_dbi_result_get_string_copy(dbi_result dbires, const char* fieldname) {
  const char* result;
  char* myresult;
  unsigned short n_field_type;
  size_t n_stringsize;

  n_field_type = dbi_result_get_field_type(dbires, fieldname);

  if (n_field_type == DBI_TYPE_BINARY) {
    /* binary strings are returned without a terminating \0 so we have
       to bend over backwards to treat it as a normal string */
    result = (const char*)dbi_result_get_binary(dbires, fieldname);
    if (!result || my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      n_stringsize = dbi_result_get_field_length(dbires, fieldname);

      /* need one extra byte for a terminating \0 */
      myresult = malloc(n_stringsize+1);
      if (myresult == NULL) {
	return NULL;
      }
      memcpy(myresult, result, n_stringsize);
      myresult[n_stringsize] = '\0'; /* terminate string */
      return myresult;
    }
  }
  else if (n_field_type == DBI_TYPE_STRING) {
    result = dbi_result_get_string_copy(dbires, fieldname);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      return (char*)result;
    }
  }
  else {
    /* should never happen */
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  my_dbi_result_get_string_copy_idx(): retrieves a given field which is either a
                            string or a binary string from a query result

  char* my_dbi_result_get_string_copy_idx returns a pointer to a string containing the 
                     requested field element, or NULL in case something
		     went wrong. The returned string must be freed by the
		     calling function

  dbi_result dbires database query result, pointing to the current
                    dataset

  unsigned int idx index of field to retrieve (1-base)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* my_dbi_result_get_string_copy_idx(dbi_result dbires, unsigned int idx) {
  const char* result;
  char* myresult;
  unsigned short n_field_type;
  size_t n_stringsize;
/*   char debug_msg[128]; */

  n_field_type = dbi_result_get_field_type_idx(dbires, idx);

/*   sprintf(debug_msg, "n_field_type went to %d", n_field_type); */
/*   LOG_PRINT(LOG_DEBUG, debug_msg); */

  if (n_field_type == DBI_TYPE_BINARY) {
    /* binary strings are returned without a terminating \0 so we have
       to bend over backwards to treat it as a normal string */
    result = (const char*)dbi_result_get_binary_idx(dbires, idx);
    if (!result || my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
      return NULL;
    }
    else {
      n_stringsize = dbi_result_get_field_length_idx(dbires, idx);

      /* need one extra byte for a terminating \0 */
      myresult = malloc(n_stringsize+1);
      if (myresult == NULL) {
	return NULL;
      }
      memcpy(myresult, result, n_stringsize);
      myresult[n_stringsize] = '\0'; /* terminate string */
      return myresult;
    }
  }
  else if (n_field_type == DBI_TYPE_STRING) {
    result = dbi_result_get_string_copy_idx(dbires, idx);
/*     if (!result) { */
/*       LOG_PRINT(LOG_DEBUG, "result went to NULL"); */
/*     } */
    if (!result || my_dbi_conn_error_flag(dbi_result_get_conn(dbires))) {
/*        sprintf(debug_msg, "error flag went to %d, idx was %d", my_dbi_conn_error_flag(dbi_result_get_conn(dbires)), idx); */
/*       LOG_PRINT(LOG_DEBUG, debug_msg); */
      return NULL;
    }
    else {
      return (char*)result;
    }
  }
  else {
    /* should never happen */
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  my_dbi_result_get_binary_copy(): retrieves a given field which is a
                             binary string from a query result

  char* my_dbi_result_get_binary_copy returns a pointer to a string 
                     containing the requested field element, or NULL
		     in case something went wrong. The returned string
		     must be freed by the calling function

  dbi_result Result database query result, pointing to the current
                    dataset

  const char* fieldname name of the field to retrieve

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* my_dbi_result_get_binary_copy(dbi_result Result, const char* fieldname) {
  /* this is a helper function that should be dropped if libdbi accepts
     the patch for dbi_result_get_binary. The issue is whether or not
     a terminating \0 is returned by the dbi function or not. This
     implementation is necessary if dbi does *not* return the \0 */

  size_t n_stringsize;
  char *myresult;
  const char *result;
  const char *errstring;
  dbi_conn conn;

  conn = dbi_result_get_conn(Result);

  result = (const char*)dbi_result_get_binary(Result, fieldname);

  if (my_dbi_conn_error_flag(conn)) {
    dbi_conn_error(conn, &errstring);
    LOG_PRINT(LOG_WARNING, errstring);
    return NULL;
  }

  n_stringsize = dbi_result_get_field_length(Result, fieldname);

  /* need one extra byte for a terminating \0 */
  myresult = malloc(n_stringsize+1);
  if (myresult == NULL) {
    LOG_PRINT(LOG_WARNING, "out of memory");
    return NULL;
  }
  memcpy(myresult, result, n_stringsize);
  myresult[n_stringsize] = '\0'; /* terminate string */
  return myresult;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  my_dbi_result_get_string(): retrieves a given TEXT field

  const char* my_dbi_result_get_string returns a pointer to a string 
                     containing the requested field element, or NULL
		     in case something went wrong.

  dbi_result Result database query result, pointing to the current
                    dataset

  const char* fieldname name of the field to retrieve

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* my_dbi_result_get_string(dbi_result Result, const char* fieldname) {
  const char* result;
  unsigned short n_field_type;

  /* this kludgy function is necessary because MySQL treats TEXT fields
     as binary data */
  n_field_type = dbi_result_get_field_type(Result, fieldname);

  if (n_field_type == DBI_TYPE_BINARY) {
    /* this implementation assumes that binary strings are
       returned by the mysql driver including a trailing \0 */
    result = (const char*)dbi_result_get_binary(Result, fieldname);
    if (!result && my_dbi_conn_error_flag(dbi_result_get_conn(Result))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else if (n_field_type == DBI_TYPE_STRING) {
    result = dbi_result_get_string(Result, fieldname);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(Result))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    /* should never happen */
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  my_dbi_result_get_string_idx(): retrieves a given TEXT field

  const char* my_dbi_result_get_string_idx returns a pointer to a string 
                     containing the requested field element, or NULL
		     in case something went wrong.

  dbi_result Result database query result, pointing to the current
                    dataset

  unsigned int idx index of the field to retrieve (1-based)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* my_dbi_result_get_string_idx(dbi_result Result, unsigned int idx) {
  const char* result;
  unsigned short n_field_type;

  /* this kludgy function is necessary because MySQL treats TEXT fields
     as binary data */
  n_field_type = dbi_result_get_field_type_idx(Result, idx);

  if (n_field_type == DBI_TYPE_BINARY) {
    /* this implementation assumes that binary strings are
       returned by the mysql driver including a trailing \0 */
    result = (const char*)dbi_result_get_binary_idx(Result, idx);
    if (!result || my_dbi_conn_error_flag(dbi_result_get_conn(Result))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else if (n_field_type == DBI_TYPE_STRING) {
    result = dbi_result_get_string_idx(Result, idx);
    if (my_dbi_conn_error_flag(dbi_result_get_conn(Result))) {
      return NULL;
    }
    else {
      return result;
    }
  }
  else {
    /* should never happen */
    return NULL;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  get_author_type_string(): returns a string that denotes the
                author type depending on the driver

  const char* get_author_type_string returns a ptr to the result string
                 or NULL in case of an unsupported driver

  dbi_driver driver ptr to a database driver structure

  int type 1 = primary author, 2 = secondary author, 3 = tertiary author

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
const char* get_author_type_string(dbi_driver driver, int type) {

  if (!strcmp(my_dbi_driver_get_cap(driver, "enum"), "t")) {
    return author_type_string[0][type-1];
  }
  else {
    return author_type_string[1][type-1];
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  is_in_list(): checks from a query result whether a given reference is
                in the personal reference list of a given user

  int is_in_list returns 1 if the reference is in the list, 0 if not,
                 -1 if some error occurs

  dbi_result dbires database query result, pointing to the current
                    dataset

  char* username ptr to string with a username

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int is_in_list(dbi_result dbires, char* username) {
  char *sql_command;
  char *quoted_username;
  unsigned long long n_id;
  dbi_result dbires1;
  dbi_conn conn;

  sql_command = malloc(256); 

  if (sql_command == NULL) {
    return -1;
  }

  conn = dbi_result_get_conn(dbires);

  quoted_username = mstrdup(username);
  if (!quoted_username) {
    free(sql_command);
    return -1;
  }
  if (dbi_conn_quote_string(conn, &quoted_username) == 0) {
    free(quoted_username);
    free(sql_command);
    return -1;
  }

  n_id = my_dbi_result_get_idval(dbires, "refdb_id");

  if (username != NULL && !my_dbi_conn_error_flag(conn)) {
    sprintf(sql_command, "SELECT t_xuser.xuser_id FROM t_xuser INNER JOIN t_user ON t_xuser.user_id=t_user.user_id WHERE t_user.user_name=%s AND t_xuser.refdb_id="ULLSPEC, quoted_username, (unsigned long long)n_id);
  }
  else {
    free(quoted_username);
    free(sql_command);
    return -1; /* should never happen */
  }

  free(quoted_username);
  LOG_PRINT(LOG_DEBUG, sql_command);
  dbires1 = dbi_conn_query(dbi_result_get_conn(dbires), sql_command);
  free(sql_command);
  
  if (!dbires1) {
    return -1;
  }

  if (dbi_result_next_row(dbires1)) {
    dbi_result_free(dbires1);
    return 1;
  }
  else {
    dbi_result_free(dbires1);
    return 0;
  }
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  sgml_entitize() replaces special characters with entities. The
                  replacement is done according to an array of
                  char/string pairs that has to be provided by the
                  calling function.
		  One source for entities and their Unicode equivalents:
		  http://www.w3.org/TR/2000/WD-MathML2-20000211/bycodes.html

  char* sgml_entitize returns a pointer to the converted string. This
                  may be different from the original value of the
		  passed pointer, so after calling this function only
		  the returned value should be used. The function also
		  modifies the value of the passed pointer to buffer.
		  If the function is successful, the return value and
		  the current value of the passed pointer will be
                  identical. The return value is NULL if an error
                  occurred. In this case, the current value of the
		  passed pointer can still be used to access the 
		  converted string as it was before the error.
		  The buffer will be reallocated if needed, and the
		  allocated length equals the length of the resulting
		  string.

  char** buffer pointer to a pointer to the string that will be
                  entitized

  int n_ref_format REF* type (see outformats.h)

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
char* sgml_entitize(char** buffer, int n_ref_format) {
  int numents = 0;
  int i = 0;
  char *new_buffer;
  char *token, *the_end;

  struct charent* the_ents;
  struct charent sgml_ents[7] = { /* lookup table for sgml */
    {"&", 1, "&amp;"},
    {"<", 1, "&lt;"},
    {">", 1, "&gt;"},
    {{226, 128, 148, 0}, 3, "&mdash;"}, /* 0x2014 */
    {{226, 128, 152, 0}, 3, "&lsquo;"}, /* 0x2018 */
    {{226, 128, 153, 0}, 3, "&rsquo;"}, /* 0x2019 */
    {"", 0, ""}
  };

  struct charent xml_ents[7] = { /*  lookup table for xml */
    {"&", 1, "&amp;"},
    {"<", 1, "&lt;"},
    {">", 1, "&gt;"},
    {"", 0, ""}
  };

  switch (n_ref_format) {
  case REFRTF:
    /* for RTF output, replace input buffer with escaped version */
    new_buffer = rtf_escape_string(*buffer);
    if (new_buffer) {
      free(*buffer);
      *buffer = new_buffer;
      return new_buffer;
    }
    else {
      return NULL;
    }
    break;
  case REFDOCBKX:
  case REFTEIX:
  case RISX:
  case REFXHTML:
  case XNOTE:
  case REFCITATIONLISTX:
  case REFMODS:
  case REFDOCBKX5:
  case REFTEIX5:
    the_ents = xml_ents;
    break;
  default:
    the_ents = sgml_ents;
    break;
  }

  while (the_ents[i].len != 0) {
  
    numents = count_the_flowers(*buffer, the_ents[i].letter, the_ents[i].len);
/*     printf("numents for %s went to %d\n", the_ents[i].letter, numents); */
    
    if (numents > 0) {
      if ((new_buffer = realloc(*buffer, strlen(*buffer) + ((strlen(the_ents[i].entity))*(numents+1)))) == NULL) {
	return NULL;
      }
      else {
	*buffer = new_buffer;
      }
      
      token = strstr(*buffer, the_ents[i].letter);
      the_end = &((*buffer)[strlen(*buffer)-1]);

      while (token != NULL) {
	char* next_amp;
	char* next_sc;
	char* next_sp;

/*  	printf("token went to:%d<<letter went to %s\n", (int)*token, the_ents[i].letter); */
	/* replace ampersand only if it does not start an entity */
	/* get pointers to the next ampersand and semicolon, if any,
	   and see which one is closer */
	next_amp = strchr(token+1, (int)'&');
	next_sc = strchr(token+1, (int)';');
	next_sp = strchr(token+1, (int)' ');

	if (*(the_ents[i].letter) != '&' || compare_ptr(&next_sc, &next_amp) != -1 || compare_ptr(&next_sp, &next_sc) != 1) {
	  replace_char_string(token, the_ents[i].entity, the_ents[i].len);
	  /* adjust the end using the number of chars added */
	  the_end += strlen(the_ents[i].entity)-the_ents[i].len;
	}
	token = (token + the_ents[i].len > the_end) ? NULL:strstr(token+the_ents[i].len, the_ents[i].letter);
      }
    }
    i++;
  }
  return *buffer;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  load_style(): loads the style information for a particular publication
                type

  dbi_result load_style returns query result if ok, NULL if an error occurred

  const char* pubtype ptr to string with the publication type

  unsigned int citstyle_id the ID of the citation style

  dbi_conn conn database connection

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
dbi_result load_style(const char* pubtype, unsigned int citstyle_id, dbi_conn conn) {
  char* sql_command;
  const char *drivername;

  /* get memory for sql command buffer */
  sql_command = malloc(8192);
  if (!sql_command) {
    LOG_PRINT(LOG_WARNING, "out of memory");
    return NULL;
  }
  drivername = dbi_driver_get_name(dbi_conn_get_driver(conn));

  /*
1	ID
2	AUTHORLISTSTYLE
3	EDITORLISTSTYLE
4	SEDITORLISTSTYLE
5	ALLALISTSTYLE
6	AUTHORLISTALTERNATESTYLE
7	EDITORLISTALTERNATESTYLE
8	SEDITORLISTALTERNATESTYLE
9	ALLALISTALTERNATESTYLE
10	AUTHORLISTALTERNATETEXT
11	EDITORLISTALTERNATETEXT
12	SEDITORLISTALTERNATETEXT
13	ALLALISTALTERNATETEXT
14	AUTHORLISTABBREVIATEFIRST
15	EDITORLISTABBREVIATEFIRST
16	SEDITORLISTABBREVIATEFIRST
17	ALLALISTABBREVIATEFIRST
18	AUTHORLISTABBREVIATESUBSEQ
19	EDITORLISTABBREVIATESUBSEQ
20	SEDITORLISTABBREVIATESUBSEQ
21	ALLALISTABBREVIATESUBSEQ
22	AUTHORLISTABBREVIATEFIRSTMAXAUTHOR
23	EDITORLISTABBREVIATEFIRSTMAXAUTHOR
24	SEDITORLISTABBREVIATEFIRSTMAXAUTHOR
25	ALLALISTABBREVIATEFIRSTMAXAUTHOR
26	AUTHORLISTABBREVIATESUBSEQMAXAUTHOR
27	EDITORLISTABBREVIATESUBSEQMAXAUTHOR
28	SEDITORLISTABBREVIATESUBSEQMAXAUTHOR
29	ALLALISTABBREVIATESUBSEQMAXAUTHOR
30	AUTHORLISTABBREVIATEFIRSTDISPLAYAUTHOR
31	EDITORLISTABBREVIATEFIRSTDISPLAYAUTHOR
32	SEDITORLISTABBREVIATEFIRSTDISPLAYAUTHOR
33	ALLALISTABBREVIATEFIRSTDISPLAYAUTHOR
34	AUTHORLISTABBREVIATESUBSEQDISPLAYAUTHOR
35	EDITORLISTABBREVIATESUBSEQDISPLAYAUTHOR
36	SEDITORLISTABBREVIATESUBSEQDISPLAYAUTHOR
37	ALLALISTABBREVIATESUBSEQDISPLAYAUTHOR
38	AUTHORLISTAEMPTY
39	EDITORLISTAEMPTY
40	SEDITORLISTAEMPTY
41	ALLALISTAEMPTY
42	AUTHORLISTASAME
43	EDITORLISTASAME
44	SEDITORLISTASAME
45	ALLALISTASAME
46	AUTHORLISTPRECEEDING
47	EDITORLISTPRECEEDING
48	SEDITORLISTPRECEEDING
49	ALLALISTPRECEEDING
50	AUTHORLISTFOLLOWING
51	EDITORLISTFOLLOWING
52	SEDITORLISTFOLLOWING
53	ALLALISTFOLLOWING
54	AUTHORLISTAUTHORSEPSTWOSEPS
55	EDITORLISTAUTHORSEPSTWOSEPS
56	SEDITORLISTAUTHORSEPSTWOSEPS
57	ALLALISTAUTHORSEPSTWOSEPS
58	AUTHORLISTAUTHORSEPSTHREESEPSTHREESEPSEACH
59	EDITORLISTAUTHORSEPSTHREESEPSTHREESEPSEACH
60	SEDITORLISTAUTHORSEPSTHREESEPSTHREESEPSEACH
61	ALLALISTAUTHORSEPSTHREESEPSTHREESEPSEACH
62	AUTHORLISTAUTHORSEPSTHREESEPSTHREESEPSLAST
63	EDITORLISTAUTHORSEPSTHREESEPSTHREESEPSLAST
64	SEDITORLISTAUTHORSEPSTHREESEPSTHREESEPSLAST
65	ALLALISTAUTHORSEPSTHREESEPSTHREESEPSLAST
66	AUTHORLISTAUTHORNAMESNAMEFIRSTNAMEORDER
67	EDITORLISTAUTHORNAMESNAMEFIRSTNAMEORDER
68	SEDITORLISTAUTHORNAMESNAMEFIRSTNAMEORDER
69	ALLALISTAUTHORNAMESNAMEFIRSTNAMEORDER
70	AUTHORLISTAUTHORNAMESNAMEFIRSTINITIALSTYLE
71	EDITORLISTAUTHORNAMESNAMEFIRSTINITIALSTYLE
72	SEDITORLISTAUTHORNAMESNAMEFIRSTINITIALSTYLE
73	ALLALISTAUTHORNAMESNAMEFIRSTINITIALSTYLE
74	AUTHORLISTAUTHORNAMESNAMEFIRSTUPPERCASE
75	EDITORLISTAUTHORNAMESNAMEFIRSTUPPERCASE
76	SEDITORLISTAUTHORNAMESNAMEFIRSTUPPERCASE
77	ALLALISTAUTHORNAMESNAMEFIRSTUPPERCASE
78	AUTHORLISTAUTHORNAMESNAMEOTHERNAMEORDER
79	EDITORLISTAUTHORNAMESNAMEOTHERNAMEORDER
80	SEDITORLISTAUTHORNAMESNAMEOTHERNAMEORDER
81	ALLALISTAUTHORNAMESNAMEOTHERNAMEORDER
82	AUTHORLISTAUTHORNAMESNAMEOTHERINITIALSTYLE
83	EDITORLISTAUTHORNAMESNAMEOTHERINITIALSTYLE
84	SEDITORLISTAUTHORNAMESNAMEOTHERINITIALSTYLE
85	ALLALISTAUTHORNAMESNAMEOTHERINITIALSTYLE
86	AUTHORLISTAUTHORNAMESNAMEOTHERUPPERCASE
87	EDITORLISTAUTHORNAMESNAMEOTHERUPPERCASE
88	SEDITORLISTAUTHORNAMESNAMEOTHERUPPERCASE
89	ALLALISTAUTHORNAMESNAMEOTHERUPPERCASE
90	AUTHORLISTTEXTTEXTSINGLEPRECEEDING
91	EDITORLISTTEXTTEXTSINGLEPRECEEDING
92	SEDITORLISTTEXTTEXTSINGLEPRECEEDING
93	ALLALISTTEXTTEXTSINGLEPRECEEDING
94	AUTHORLISTTEXTTEXTSINGLEFOLLOWING
95	EDITORLISTTEXTTEXTSINGLEFOLLOWING
96	SEDITORLISTTEXTTEXTSINGLEFOLLOWING
97	ALLALISTTEXTTEXTSINGLEFOLLOWING
98	AUTHORLISTTEXTTEXTMULTIPLEPRECEEDING
99	EDITORLISTTEXTTEXTMULTIPLEPRECEEDING
100	SEDITORLISTTEXTTEXTMULTIPLEPRECEEDING
101	ALLALISTTEXTTEXTMULTIPLEPRECEEDING
102	AUTHORLISTTEXTTEXTMULTIPLEFOLLOWING
103	EDITORLISTTEXTTEXTMULTIPLEFOLLOWING
104	SEDITORLISTTEXTTEXTMULTIPLEFOLLOWING
105	ALLALISTTEXTTEXTMULTIPLEFOLLOWING
106	AUTHORLISTTEXTEDTEXTSINGLEPRECEEDING
107	EDITORLISTTEXTEDTEXTSINGLEPRECEEDING
108	SEDITORLISTTEXTEDTEXTSINGLEPRECEEDING
109	ALLALISTTEXTEDTEXTSINGLEPRECEEDING
110	AUTHORLISTTEXTEDTEXTSINGLEFOLLOWING
111	EDITORLISTTEXTEDTEXTSINGLEFOLLOWING
112	SEDITORLISTTEXTEDTEXTSINGLEFOLLOWING
113	ALLALISTTEXTEDTEXTSINGLEFOLLOWING
114	AUTHORLISTTEXTEDTEXTMULTIPLEPRECEEDING
115	EDITORLISTTEXTEDTEXTMULTIPLEPRECEEDING
116	SEDITORLISTTEXTEDTEXTMULTIPLEPRECEEDING
117	ALLALISTTEXTEDTEXTMULTIPLEPRECEEDING
118	AUTHORLISTTEXTEDTEXTMULTIPLEFOLLOWING
119	EDITORLISTTEXTEDTEXTMULTIPLEFOLLOWING
120	SEDITORLISTTEXTEDTEXTMULTIPLEFOLLOWING
121	ALLALISTTEXTEDTEXTMULTIPLEFOLLOWING
122	PUBDATEPRECEEDING
123	PUBDATEFOLLOWING
124	PUBDATEFORMAT
125	PUBDATESEQUENCE
126	PUBDATEMONTHFORMAT
127	PUBDATEDAYFORMAT
128	PUBDATEYEARFORMAT
129	PUBDATEPADLEADINGZERO
130	PUBDATESTYLE
131	PUBDATESECPRECEEDING
132	PUBDATESECFOLLOWING
133	PUBDATESECFORMAT
134	PUBDATESECSEQUENCE
135	PUBDATESECMONTHFORMAT
136	PUBDATESECDAYFORMAT
137	PUBDATESECYEARFORMAT
138	PUBDATESECPADLEADINGZERO
139	PUBDATESECSTYLE
140	PUBDATEALLPRECEEDING
141	PUBDATEALLFOLLOWING
142	PUBDATEALLFORMAT
143	PUBDATEALLSEQUENCE
144	PUBDATEALLMONTHFORMAT
145	PUBDATEALLDAYFORMAT
146	PUBDATEALLYEARFORMAT
147	PUBDATEALLPADLEADINGZERO
148	PUBDATEALLSTYLE
149	TITLEPRECEEDING
150	TITLEFOLLOWING
151	TITLECASE
152	TITLESTYLE
153	BOOKTITLEPRECEEDING
154	BOOKTITLEFOLLOWING
155	BOOKTITLECASE
156	BOOKTITLESTYLE
157	SERIESTITLEPRECEEDING
158	SERIESTITLEFOLLOWING
159	SERIESTITLECASE
160	SERIESTITLESTYLE
161	ALLTITLEPRECEEDING
162	ALLTITLEFOLLOWING
163	ALLTITLECASE
164	ALLTITLESTYLE
165	JOURNALNAMEPRECEEDING
166	JOURNALNAMEFOLLOWING
167	JOURNALNAMECASE
168	JOURNALNAMEDEFAULTTEXT
169	JOURNALNAMEALTERNATETEXT
170	JOURNALNAMEPUNCTUATION
171	JOURNALNAMESTYLE
172	VOLUMEPRECEEDING
173	VOLUMEFOLLOWING
174	VOLUMESTYLE
175	ISSUEPRECEEDING
176	ISSUEFOLLOWING
177	ISSUESTYLE
178	PAGESSTYLE
179	PAGESSINGLEPAGEPRECEEDING
180	PAGESSINGLEPAGEFOLLOWING
181	PAGESPAGERANGEPRECEEDING
182	PAGESPAGERANGEFOLLOWING
183	PAGESPAGERANGETYPE
184	PUBLISHERPRECEEDING
185	PUBLISHERFOLLOWING
186	PUBLISHERSTYLE
187	PUBPLACEPRECEEDING
188	PUBPLACEFOLLOWING
189	PUBPLACESTYLE
190	PAGESPRECEEDING
191	PAGESFOLLOWING
192	REFNUMBERPRECEEDING
193	REFNUMBERFOLLOWING
194	REFNUMBERSTYLE
195	PUBDATEFIRSTSEP
196	PUBDATESECONDSEP
197	PUBDATESECFIRSTSEP
198	PUBDATESECSECONDSEP
199	PUBDATEALLFIRSTSEP
200	PUBDATEALLSECONDSEP
201	PAGESPAGERANGERANGESEPARATOR
202	SERIALPRECEEDING
203	SERIALFOLLOWING
204	SERIALSTYLE
205	ADDRESSPRECEEDING
206	ADDRESSFOLLOWING
207	ADDRESSSTYLE
208	USERDEF1PRECEEDING
209	USERDEF1FOLLOWING
210	USERDEF1STYLE
211	USERDEF2PRECEEDING
212	USERDEF2FOLLOWING
213	USERDEF2STYLE
214	USERDEF3PRECEEDING
215	USERDEF3FOLLOWING
216	USERDEF3STYLE
217	USERDEF4PRECEEDING
218	USERDEF4FOLLOWING
219	USERDEF4STYLE
220	USERDEF5PRECEEDING
221	USERDEF5FOLLOWING
222	USERDEF5STYLE
232	NOTESPRECEEDING
233	NOTESFOLLOWING
234	NOTESSTYLE
235	ABSTRACTPRECEEDING
236	ABSTRACTFOLLOWING
237	ABSTRACTSTYLE
TYPEOFWORKPRECEEDING
TYPEOFWORKFOLLOWING
TYPEOFWORKSTYLE
AREAPRECEEDING
AREAFOLLOWING
AREASTYLE
OSTYPEPRECEEDING
OSTYPEFOLLOWING
OSTYPESTYLE
DEGREEPRECEEDING
DEGREEFOLLOWING
DEGREESTYLE
RUNNINGTIMEPRECEEDING
RUNNINGTIMEFOLLOWING
RUNNINGTIMESTYLE
CLASSCODEINTLPRECEEDING
CLASSCODEINTLFOLLOWING
CLASSCODEINTLSTYLE
CLASSCODEUSPRECEEDING
CLASSCODEUSFOLLOWING
CLASSCODEUSSTYLE
SENDEREMAILPRECEEDING
SENDEREMAILFOLLOWING
SENDEREMAILSTYLE
RECIPIENTEMAILPRECEEDING
RECIPIENTEMAILFOLLOWING
RECIPIENTEMAILSTYLE
MEDIATYPEPRECEEDING
MEDIATYPEFOLLOWING
MEDIATYPESTYLE
NUMVOLUMESPRECEEDING
NUMVOLUMESFOLLOWING
NUMVOLUMESSTYLE
EDITIONPRECEEDING
EDITIONFOLLOWING
EDITIONSTYLE
COMPUTERPRECEEDING
COMPUTERFOLLOWING
COMPUTERSTYLE
CONFERENCELOCATIONPRECEEDING
CONFERENCELOCATIONFOLLOWING
CONFERENCELOCATIONSTYLE
REGISTRYNUMPRECEEDING
REGISTRYNUMFOLLOWING
REGISTRYNUMSTYLE
CLASSIFICATIONPRECEEDING
CLASSIFICATIONFOLLOWING
CLASSIFICATIONSTYLE
SECTIONPRECEEDING
SECTIONFOLLOWING
SECTIONSTYLE
PAMPHLETNUMPRECEEDING
PAMPHLETNUMFOLLOWING
PAMPHLETNUMSTYLE
CHAPTERNUMPRECEEDING
CHAPTERNUMFOLLOWING
CHAPTERNUMSTYLE
238	LINK0PRECEEDING
239	LINK0FOLLOWING
240	LINK0STYLE
241	LINK1PRECEEDING
242	LINK1FOLLOWING
243	LINK1STYLE
244	LINK2PRECEEDING
245	LINK2FOLLOWING
246	LINK2STYLE
247	LINK3PRECEEDING
248	LINK3FOLLOWING
249	LINK3STYLE
250	LINK4PRECEEDING
251	LINK4FOLLOWING
252	LINK4STYLE
253	CITEKEYPRECEEDING
254	CITEKEYFOLLOWING
255	CITEKEYSTYLE
   */

  /* now retrieve matching style information from REFSTYLE into*/
  if (!strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
    sprintf(sql_command, "SELECT ID, QSTYLE, XSTYLE, YSTYLE, ZSTYLE, QALTERNATESTYLE, XALTERNATESTYLE, YALTERNATESTYLE, ZALTERNATESTYLE, QALTERNATETEXT, XALTERNATETEXT, YALTERNATETEXT, ZALTERNATETEXT, QABBREVIATEFIRST, XABBREVIATEFIRST, YABBREVIATEFIRST, ZABBREVIATEFIRST, QABBREVIATESUBSEQ, XABBREVIATESUBSEQ, YABBREVIATESUBSEQ, ZABBREVIATESUBSEQ, QABBREVIATEFIRSTMAXAUTHOR, XABBREVIATEFIRSTMAXAUTHOR, YABBREVIATEFIRSTMAXAUTHOR, ZABBREVIATEFIRSTMAXAUTHOR, QABBREVIATESUBSEQMAXAUTHOR, XABBREVIATESUBSEQMAXAUTHOR, YABBREVIATESUBSEQMAXAUTHOR, ZABBREVIATESUBSEQMAXAUTHOR, QABBREVIATEFIRSTDISPLAYAUTHOR, XABBREVIATEFIRSTDISPLAYAUTHOR, YABBREVIATEFIRSTDISPLAYAUTHOR, ZABBREVIATEFIRSTDISPLAYAUTHOR, QABBREVIATESUBSEQDISPLAYAUTHOR, XABBREVIATESUBSEQDISPLAYAUTHOR, YABBREVIATESUBSEQDISPLAYAUTHOR, ZABBREVIATESUBSEQDISPLAYAUTHOR, QAEMPTY, XAEMPTY, YAEMPTY, ZAEMPTY, QASAME, XASAME, YASAME, ZASAME, QPRECEEDING, XPRECEEDING, YPRECEEDING, ZPRECEEDING, QFOLLOWING, XFOLLOWING, YFOLLOWING, ZFOLLOWING, QAUTHORSEPSTWOSEPS, XAUTHORSEPSTWOSEPS, YAUTHORSEPSTWOSEPS, ZAUTHORSEPSTWOSEPS, QAUTHORSEPSTHREESEPSTHREESEPSEACH, XAUTHORSEPSTHREESEPSTHREESEPSEACH, YAUTHORSEPSTHREESEPSTHREESEPSEACH, ZAUTHORSEPSTHREESEPSTHREESEPSEACH, QAUTHORSEPSTHREESEPSTHREESEPSLAST, XAUTHORSEPSTHREESEPSTHREESEPSLAST, YAUTHORSEPSTHREESEPSTHREESEPSLAST, ZAUTHORSEPSTHREESEPSTHREESEPSLAST, QAUTHORNAMESNAMEFIRSTNAMEORDER, XAUTHORNAMESNAMEFIRSTNAMEORDER, YAUTHORNAMESNAMEFIRSTNAMEORDER, ZAUTHORNAMESNAMEFIRSTNAMEORDER, QAUTHORNAMESNAMEFIRSTINITIALSTYLE, XAUTHORNAMESNAMEFIRSTINITIALSTYLE, YAUTHORNAMESNAMEFIRSTINITIALSTYLE, ZAUTHORNAMESNAMEFIRSTINITIALSTYLE, QAUTHORNAMESNAMEFIRSTUPPERCASE, XAUTHORNAMESNAMEFIRSTUPPERCASE, YAUTHORNAMESNAMEFIRSTUPPERCASE, ZAUTHORNAMESNAMEFIRSTUPPERCASE, QAUTHORNAMESNAMEOTHERNAMEORDER, XAUTHORNAMESNAMEOTHERNAMEORDER, YAUTHORNAMESNAMEOTHERNAMEORDER, ZAUTHORNAMESNAMEOTHERNAMEORDER, QAUTHORNAMESNAMEOTHERINITIALSTYLE, XAUTHORNAMESNAMEOTHERINITIALSTYLE, YAUTHORNAMESNAMEOTHERINITIALSTYLE, ZAUTHORNAMESNAMEOTHERINITIALSTYLE, QAUTHORNAMESNAMEOTHERUPPERCASE, XAUTHORNAMESNAMEOTHERUPPERCASE, YAUTHORNAMESNAMEOTHERUPPERCASE, ZAUTHORNAMESNAMEOTHERUPPERCASE, QTEXTTEXTSINGLEPRECEEDING, XTEXTTEXTSINGLEPRECEEDING, YTEXTTEXTSINGLEPRECEEDING, ZTEXTTEXTSINGLEPRECEEDING, QTEXTTEXTSINGLEFOLLOWING, XTEXTTEXTSINGLEFOLLOWING, YTEXTTEXTSINGLEFOLLOWING, ZTEXTTEXTSINGLEFOLLOWING, QTEXTTEXTMULTIPLEPRECEEDING, XTEXTTEXTMULTIPLEPRECEEDING, YTEXTTEXTMULTIPLEPRECEEDING, ZTEXTTEXTMULTIPLEPRECEEDING, QTEXTTEXTMULTIPLEFOLLOWING, XTEXTTEXTMULTIPLEFOLLOWING, YTEXTTEXTMULTIPLEFOLLOWING, ZTEXTTEXTMULTIPLEFOLLOWING, QTEXTEDTEXTSINGLEPRECEEDING, XTEXTEDTEXTSINGLEPRECEEDING, YTEXTEDTEXTSINGLEPRECEEDING, ZTEXTEDTEXTSINGLEPRECEEDING, QTEXTEDTEXTSINGLEFOLLOWING, XTEXTEDTEXTSINGLEFOLLOWING, YTEXTEDTEXTSINGLEFOLLOWING, ZTEXTEDTEXTSINGLEFOLLOWING, QTEXTEDTEXTMULTIPLEPRECEEDING, XTEXTEDTEXTMULTIPLEPRECEEDING, YTEXTEDTEXTMULTIPLEPRECEEDING, ZTEXTEDTEXTMULTIPLEPRECEEDING, QTEXTEDTEXTMULTIPLEFOLLOWING, XTEXTEDTEXTMULTIPLEFOLLOWING, YTEXTEDTEXTMULTIPLEFOLLOWING, ZTEXTEDTEXTMULTIPLEFOLLOWING, PUBDATEPRECEEDING, PUBDATEFOLLOWING, PUBDATEFORMAT, PUBDATESEQUENCE, PUBDATEMONTHFORMAT, PUBDATEDAYFORMAT, PUBDATEYEARFORMAT, PUBDATEPADLEADINGZERO, PUBDATESTYLE, PUBDATESECPRECEEDING, PUBDATESECFOLLOWING, PUBDATESECFORMAT, PUBDATESECSEQUENCE, PUBDATESECMONTHFORMAT, PUBDATESECDAYFORMAT, PUBDATESECYEARFORMAT, PUBDATESECPADLEADINGZERO, PUBDATESECSTYLE, PUBDATEALLPRECEEDING, PUBDATEALLFOLLOWING, PUBDATEALLFORMAT, PUBDATEALLSEQUENCE, PUBDATEALLMONTHFORMAT, PUBDATEALLDAYFORMAT, PUBDATEALLYEARFORMAT, PUBDATEALLPADLEADINGZERO, PUBDATEALLSTYLE, TITLEPRECEEDING, TITLEFOLLOWING, TITLECASE, TITLESTYLE, BOOKTITLEPRECEEDING, BOOKTITLEFOLLOWING, BOOKTITLECASE, BOOKTITLESTYLE, SERIESTITLEPRECEEDING, SERIESTITLEFOLLOWING, SERIESTITLECASE, SERIESTITLESTYLE, ALLTITLEPRECEEDING, ALLTITLEFOLLOWING, ALLTITLECASE, ALLTITLESTYLE, JOURNALNAMEPRECEEDING, JOURNALNAMEFOLLOWING, JOURNALNAMECASE, JOURNALNAMEDEFAULTTEXT, JOURNALNAMEALTERNATETEXT, JOURNALNAMEPUNCTUATION, JOURNALNAMESTYLE, VOLUMEPRECEEDING, VOLUMEFOLLOWING, VOLUMESTYLE, ISSUEPRECEEDING, ISSUEFOLLOWING, ISSUESTYLE, PAGESSTYLE, PAGESSINGLEPAGEPRECEEDING, PAGESSINGLEPAGEFOLLOWING, PAGESPAGERANGEPRECEEDING, PAGESPAGERANGEFOLLOWING, PAGESPAGERANGETYPE, PUBLISHERPRECEEDING, PUBLISHERFOLLOWING, PUBLISHERSTYLE, PUBPLACEPRECEEDING, PUBPLACEFOLLOWING, PUBPLACESTYLE, PAGESPRECEEDING, PAGESFOLLOWING, REFNUMBERPRECEEDING, REFNUMBERFOLLOWING, REFNUMBERSTYLE, PUBDATEFIRSTSEP, PUBDATESECONDSEP, PUBDATESECFIRSTSEP, PUBDATESECSECONDSEP, PUBDATEALLFIRSTSEP, PUBDATEALLSECONDSEP, PAGESPAGERANGERANGESEPARATOR, SERIALPRECEEDING, SERIALFOLLOWING, SERIALSTYLE, ADDRESSPRECEEDING, ADDRESSFOLLOWING, ADDRESSSTYLE, USERDEF1PRECEEDING, USERDEF1FOLLOWING, USERDEF1STYLE, USERDEF2PRECEEDING, USERDEF2FOLLOWING, USERDEF2STYLE, USERDEF3PRECEEDING, USERDEF3FOLLOWING, USERDEF3STYLE, USERDEF4PRECEEDING, USERDEF4FOLLOWING, USERDEF4STYLE, USERDEF5PRECEEDING, USERDEF5FOLLOWING, USERDEF5STYLE, NOTESPRECEEDING, NOTESFOLLOWING, NOTESSTYLE, ABSTRACTPRECEEDING, ABSTRACTFOLLOWING, ABSTRACTSTYLE, TYPEOFWORKPRECEEDING, TYPEOFWORKFOLLOWING, TYPEOFWORKSTYLE, AREAPRECEEDING, AREAFOLLOWING, AREASTYLE, OSTYPEPRECEEDING, OSTYPEFOLLOWING, OSTYPESTYLE, DEGREEPRECEEDING, DEGREEFOLLOWING, DEGREESTYLE, RUNNINGTIMEPRECEEDING, RUNNINGTIMEFOLLOWING, RUNNINGTIMESTYLE, CLASSCODEINTLPRECEEDING, CLASSCODEINTLFOLLOWING, CLASSCODEINTLSTYLE, CLASSCODEUSPRECEEDING, CLASSCODEUSFOLLOWING, CLASSCODEUSSTYLE, SENDEREMAILPRECEEDING, SENDEREMAILFOLLOWING, SENDEREMAILSTYLE, RECIPIENTEMAILPRECEEDING, RECIPIENTEMAILFOLLOWING, RECIPIENTEMAILSTYLE, MEDIATYPEPRECEEDING, MEDIATYPEFOLLOWING, MEDIATYPESTYLE, NUMVOLUMESPRECEEDING, NUMVOLUMESFOLLOWING, NUMVOLUMESSTYLE, EDITIONPRECEEDING, EDITIONFOLLOWING, EDITIONSTYLE, COMPUTERPRECEEDING, COMPUTERFOLLOWING, COMPUTERSTYLE, CONFERENCELOCATIONPRECEEDING, CONFERENCELOCATIONFOLLOWING, CONFERENCELOCATIONSTYLE, REGISTRYNUMPRECEEDING, REGISTRYNUMFOLLOWING, REGISTRYNUMSTYLE, CLASSIFICATIONPRECEEDING, CLASSIFICATIONFOLLOWING, CLASSIFICATIONSTYLE, SECTIONPRECEEDING, SECTIONFOLLOWING, SECTIONSTYLE, PAMPHLETNUMPRECEEDING, PAMPHLETNUMFOLLOWING, PAMPHLETNUMSTYLE, CHAPTERNUMPRECEEDING, CHAPTERNUMFOLLOWING, CHAPTERNUMSTYLE, LINK0PRECEEDING, LINK0FOLLOWING, LINK0STYLE, LINK1PRECEEDING, LINK1FOLLOWING, LINK1STYLE, LINK2PRECEEDING, LINK2FOLLOWING, LINK2STYLE, LINK3PRECEEDING, LINK3FOLLOWING, LINK3STYLE, LINK4PRECEEDING, LINK4FOLLOWING, LINK4STYLE, CITEKEYPRECEEDING, CITEKEYFOLLOWING, CITEKEYSTYLE from %s.REFSTYLE where PUBTYPE='%s' and CITSTYLEID=%u", main_db, pubtype, citstyle_id);
  }
  else {
    sprintf(sql_command, "SELECT ID, QSTYLE, XSTYLE, YSTYLE, ZSTYLE, QALTERNATESTYLE, XALTERNATESTYLE, YALTERNATESTYLE, ZALTERNATESTYLE, QALTERNATETEXT, XALTERNATETEXT, YALTERNATETEXT, ZALTERNATETEXT, QABBREVIATEFIRST, XABBREVIATEFIRST, YABBREVIATEFIRST, ZABBREVIATEFIRST, QABBREVIATESUBSEQ, XABBREVIATESUBSEQ, YABBREVIATESUBSEQ, ZABBREVIATESUBSEQ, QABBREVIATEFIRSTMAXAUTHOR, XABBREVIATEFIRSTMAXAUTHOR, YABBREVIATEFIRSTMAXAUTHOR, ZABBREVIATEFIRSTMAXAUTHOR, QABBREVIATESUBSEQMAXAUTHOR, XABBREVIATESUBSEQMAXAUTHOR, YABBREVIATESUBSEQMAXAUTHOR, ZABBREVIATESUBSEQMAXAUTHOR, QABBREVIATEFIRSTDISPLAYAUTHOR, XABBREVIATEFIRSTDISPLAYAUTHOR, YABBREVIATEFIRSTDISPLAYAUTHOR, ZABBREVIATEFIRSTDISPLAYAUTHOR, QABBREVIATESUBSEQDISPLAYAUTHOR, XABBREVIATESUBSEQDISPLAYAUTHOR, YABBREVIATESUBSEQDISPLAYAUTHOR, ZABBREVIATESUBSEQDISPLAYAUTHOR, QAEMPTY, XAEMPTY, YAEMPTY, ZAEMPTY, QASAME, XASAME, YASAME, ZASAME, QPRECEEDING, XPRECEEDING, YPRECEEDING, ZPRECEEDING, QFOLLOWING, XFOLLOWING, YFOLLOWING, ZFOLLOWING, QAUTHORSEPSTWOSEPS, XAUTHORSEPSTWOSEPS, YAUTHORSEPSTWOSEPS, ZAUTHORSEPSTWOSEPS, QAUTHORSEPSTHREESEPSTHREESEPSEACH, XAUTHORSEPSTHREESEPSTHREESEPSEACH, YAUTHORSEPSTHREESEPSTHREESEPSEACH, ZAUTHORSEPSTHREESEPSTHREESEPSEACH, QAUTHORSEPSTHREESEPSTHREESEPSLAST, XAUTHORSEPSTHREESEPSTHREESEPSLAST, YAUTHORSEPSTHREESEPSTHREESEPSLAST, ZAUTHORSEPSTHREESEPSTHREESEPSLAST, QAUTHORNAMESNAMEFIRSTNAMEORDER, XAUTHORNAMESNAMEFIRSTNAMEORDER, YAUTHORNAMESNAMEFIRSTNAMEORDER, ZAUTHORNAMESNAMEFIRSTNAMEORDER, QAUTHORNAMESNAMEFIRSTINITIALSTYLE, XAUTHORNAMESNAMEFIRSTINITIALSTYLE, YAUTHORNAMESNAMEFIRSTINITIALSTYLE, ZAUTHORNAMESNAMEFIRSTINITIALSTYLE, QAUTHORNAMESNAMEFIRSTUPPERCASE, XAUTHORNAMESNAMEFIRSTUPPERCASE, YAUTHORNAMESNAMEFIRSTUPPERCASE, ZAUTHORNAMESNAMEFIRSTUPPERCASE, QAUTHORNAMESNAMEOTHERNAMEORDER, XAUTHORNAMESNAMEOTHERNAMEORDER, YAUTHORNAMESNAMEOTHERNAMEORDER, ZAUTHORNAMESNAMEOTHERNAMEORDER, QAUTHORNAMESNAMEOTHERINITIALSTYLE, XAUTHORNAMESNAMEOTHERINITIALSTYLE, YAUTHORNAMESNAMEOTHERINITIALSTYLE, ZAUTHORNAMESNAMEOTHERINITIALSTYLE, QAUTHORNAMESNAMEOTHERUPPERCASE, XAUTHORNAMESNAMEOTHERUPPERCASE, YAUTHORNAMESNAMEOTHERUPPERCASE, ZAUTHORNAMESNAMEOTHERUPPERCASE, QTEXTTEXTSINGLEPRECEEDING, XTEXTTEXTSINGLEPRECEEDING, YTEXTTEXTSINGLEPRECEEDING, ZTEXTTEXTSINGLEPRECEEDING, QTEXTTEXTSINGLEFOLLOWING, XTEXTTEXTSINGLEFOLLOWING, YTEXTTEXTSINGLEFOLLOWING, ZTEXTTEXTSINGLEFOLLOWING, QTEXTTEXTMULTIPLEPRECEEDING, XTEXTTEXTMULTIPLEPRECEEDING, YTEXTTEXTMULTIPLEPRECEEDING, ZTEXTTEXTMULTIPLEPRECEEDING, QTEXTTEXTMULTIPLEFOLLOWING, XTEXTTEXTMULTIPLEFOLLOWING, YTEXTTEXTMULTIPLEFOLLOWING, ZTEXTTEXTMULTIPLEFOLLOWING, QTEXTEDTEXTSINGLEPRECEEDING, XTEXTEDTEXTSINGLEPRECEEDING, YTEXTEDTEXTSINGLEPRECEEDING, ZTEXTEDTEXTSINGLEPRECEEDING, QTEXTEDTEXTSINGLEFOLLOWING, XTEXTEDTEXTSINGLEFOLLOWING, YTEXTEDTEXTSINGLEFOLLOWING, ZTEXTEDTEXTSINGLEFOLLOWING, QTEXTEDTEXTMULTIPLEPRECEEDING, XTEXTEDTEXTMULTIPLEPRECEEDING, YTEXTEDTEXTMULTIPLEPRECEEDING, ZTEXTEDTEXTMULTIPLEPRECEEDING, QTEXTEDTEXTMULTIPLEFOLLOWING, XTEXTEDTEXTMULTIPLEFOLLOWING, YTEXTEDTEXTMULTIPLEFOLLOWING, ZTEXTEDTEXTMULTIPLEFOLLOWING, PUBDATEPRECEEDING, PUBDATEFOLLOWING, PUBDATEFORMAT, PUBDATESEQUENCE, PUBDATEMONTHFORMAT, PUBDATEDAYFORMAT, PUBDATEYEARFORMAT, PUBDATEPADLEADINGZERO, PUBDATESTYLE, PUBDATESECPRECEEDING, PUBDATESECFOLLOWING, PUBDATESECFORMAT, PUBDATESECSEQUENCE, PUBDATESECMONTHFORMAT, PUBDATESECDAYFORMAT, PUBDATESECYEARFORMAT, PUBDATESECPADLEADINGZERO, PUBDATESECSTYLE, PUBDATEALLPRECEEDING, PUBDATEALLFOLLOWING, PUBDATEALLFORMAT, PUBDATEALLSEQUENCE, PUBDATEALLMONTHFORMAT, PUBDATEALLDAYFORMAT, PUBDATEALLYEARFORMAT, PUBDATEALLPADLEADINGZERO, PUBDATEALLSTYLE, TITLEPRECEEDING, TITLEFOLLOWING, TITLECASE, TITLESTYLE, BOOKTITLEPRECEEDING, BOOKTITLEFOLLOWING, BOOKTITLECASE, BOOKTITLESTYLE, SERIESTITLEPRECEEDING, SERIESTITLEFOLLOWING, SERIESTITLECASE, SERIESTITLESTYLE, ALLTITLEPRECEEDING, ALLTITLEFOLLOWING, ALLTITLECASE, ALLTITLESTYLE, JOURNALNAMEPRECEEDING, JOURNALNAMEFOLLOWING, JOURNALNAMECASE, JOURNALNAMEDEFAULTTEXT, JOURNALNAMEALTERNATETEXT, JOURNALNAMEPUNCTUATION, JOURNALNAMESTYLE, VOLUMEPRECEEDING, VOLUMEFOLLOWING, VOLUMESTYLE, ISSUEPRECEEDING, ISSUEFOLLOWING, ISSUESTYLE, PAGESSTYLE, PAGESSINGLEPAGEPRECEEDING, PAGESSINGLEPAGEFOLLOWING, PAGESPAGERANGEPRECEEDING, PAGESPAGERANGEFOLLOWING, PAGESPAGERANGETYPE, PUBLISHERPRECEEDING, PUBLISHERFOLLOWING, PUBLISHERSTYLE, PUBPLACEPRECEEDING, PUBPLACEFOLLOWING, PUBPLACESTYLE, PAGESPRECEEDING, PAGESFOLLOWING, REFNUMBERPRECEEDING, REFNUMBERFOLLOWING, REFNUMBERSTYLE, PUBDATEFIRSTSEP, PUBDATESECONDSEP, PUBDATESECFIRSTSEP, PUBDATESECSECONDSEP, PUBDATEALLFIRSTSEP, PUBDATEALLSECONDSEP, PAGESPAGERANGERANGESEPARATOR, SERIALPRECEEDING, SERIALFOLLOWING, SERIALSTYLE, ADDRESSPRECEEDING, ADDRESSFOLLOWING, ADDRESSSTYLE, USERDEF1PRECEEDING, USERDEF1FOLLOWING, USERDEF1STYLE, USERDEF2PRECEEDING, USERDEF2FOLLOWING, USERDEF2STYLE, USERDEF3PRECEEDING, USERDEF3FOLLOWING, USERDEF3STYLE, USERDEF4PRECEEDING, USERDEF4FOLLOWING, USERDEF4STYLE, USERDEF5PRECEEDING, USERDEF5FOLLOWING, USERDEF5STYLE, NOTESPRECEEDING, NOTESFOLLOWING, NOTESSTYLE, ABSTRACTPRECEEDING, ABSTRACTFOLLOWING, ABSTRACTSTYLE, TYPEOFWORKPRECEEDING, TYPEOFWORKFOLLOWING, TYPEOFWORKSTYLE, AREAPRECEEDING, AREAFOLLOWING, AREASTYLE, OSTYPEPRECEEDING, OSTYPEFOLLOWING, OSTYPESTYLE, DEGREEPRECEEDING, DEGREEFOLLOWING, DEGREESTYLE, RUNNINGTIMEPRECEEDING, RUNNINGTIMEFOLLOWING, RUNNINGTIMESTYLE, CLASSCODEINTLPRECEEDING, CLASSCODEINTLFOLLOWING, CLASSCODEINTLSTYLE, CLASSCODEUSPRECEEDING, CLASSCODEUSFOLLOWING, CLASSCODEUSSTYLE, SENDEREMAILPRECEEDING, SENDEREMAILFOLLOWING, SENDEREMAILSTYLE, RECIPIENTEMAILPRECEEDING, RECIPIENTEMAILFOLLOWING, RECIPIENTEMAILSTYLE, MEDIATYPEPRECEEDING, MEDIATYPEFOLLOWING, MEDIATYPESTYLE, NUMVOLUMESPRECEEDING, NUMVOLUMESFOLLOWING, NUMVOLUMESSTYLE, EDITIONPRECEEDING, EDITIONFOLLOWING, EDITIONSTYLE, COMPUTERPRECEEDING, COMPUTERFOLLOWING, COMPUTERSTYLE, CONFERENCELOCATIONPRECEEDING, CONFERENCELOCATIONFOLLOWING, CONFERENCELOCATIONSTYLE, REGISTRYNUMPRECEEDING, REGISTRYNUMFOLLOWING, REGISTRYNUMSTYLE, CLASSIFICATIONPRECEEDING, CLASSIFICATIONFOLLOWING, CLASSIFICATIONSTYLE, SECTIONPRECEEDING, SECTIONFOLLOWING, SECTIONSTYLE, PAMPHLETNUMPRECEEDING, PAMPHLETNUMFOLLOWING, PAMPHLETNUMSTYLE, CHAPTERNUMPRECEEDING, CHAPTERNUMFOLLOWING, CHAPTERNUMSTYLE, LINK0PRECEEDING, LINK0FOLLOWING, LINK0STYLE, LINK1PRECEEDING, LINK1FOLLOWING, LINK1STYLE, LINK2PRECEEDING, LINK2FOLLOWING, LINK2STYLE, LINK3PRECEEDING, LINK3FOLLOWING, LINK3STYLE, LINK4PRECEEDING, LINK4FOLLOWING, LINK4STYLE, CITEKEYPRECEEDING, CITEKEYFOLLOWING, CITEKEYSTYLE from REFSTYLE where PUBTYPE='%s' and CITSTYLEID=%u", pubtype, citstyle_id);
  }

  LOG_PRINT(LOG_DEBUG, sql_command);
  dbi_style_res = dbi_conn_query(conn, sql_command);

  if (!dbi_style_res) {
    dbi_conn_error(conn, (const char**)&sql_command);
    LOG_PRINT(LOG_WARNING, "CITSTYLE select failed");
    LOG_PRINT(LOG_WARNING, sql_command);
    free(sql_command);
    return NULL;
  }

  if (dbi_result_next_row(dbi_style_res) == 0) {
    /* there is no style for this citation type. Try the generic type instead */
    dbi_result_free(dbi_style_res);
    if (!strcmp(my_dbi_conn_get_cap(conn, "multiple_db"), "t")) {
      sprintf(sql_command, "SELECT ID, QSTYLE, XSTYLE, YSTYLE, ZSTYLE, QALTERNATESTYLE, XALTERNATESTYLE, YALTERNATESTYLE, ZALTERNATESTYLE, QALTERNATETEXT, XALTERNATETEXT, YALTERNATETEXT, ZALTERNATETEXT, QABBREVIATEFIRST, XABBREVIATEFIRST, YABBREVIATEFIRST, ZABBREVIATEFIRST, QABBREVIATESUBSEQ, XABBREVIATESUBSEQ, YABBREVIATESUBSEQ, ZABBREVIATESUBSEQ, QABBREVIATEFIRSTMAXAUTHOR, XABBREVIATEFIRSTMAXAUTHOR, YABBREVIATEFIRSTMAXAUTHOR, ZABBREVIATEFIRSTMAXAUTHOR, QABBREVIATESUBSEQMAXAUTHOR, XABBREVIATESUBSEQMAXAUTHOR, YABBREVIATESUBSEQMAXAUTHOR, ZABBREVIATESUBSEQMAXAUTHOR, QABBREVIATEFIRSTDISPLAYAUTHOR, XABBREVIATEFIRSTDISPLAYAUTHOR, YABBREVIATEFIRSTDISPLAYAUTHOR, ZABBREVIATEFIRSTDISPLAYAUTHOR, QABBREVIATESUBSEQDISPLAYAUTHOR, XABBREVIATESUBSEQDISPLAYAUTHOR, YABBREVIATESUBSEQDISPLAYAUTHOR, ZABBREVIATESUBSEQDISPLAYAUTHOR, QAEMPTY, XAEMPTY, YAEMPTY, ZAEMPTY, QASAME, XASAME, YASAME, ZASAME, QPRECEEDING, XPRECEEDING, YPRECEEDING, ZPRECEEDING, QFOLLOWING, XFOLLOWING, YFOLLOWING, ZFOLLOWING, QAUTHORSEPSTWOSEPS, XAUTHORSEPSTWOSEPS, YAUTHORSEPSTWOSEPS, ZAUTHORSEPSTWOSEPS, QAUTHORSEPSTHREESEPSTHREESEPSEACH, XAUTHORSEPSTHREESEPSTHREESEPSEACH, YAUTHORSEPSTHREESEPSTHREESEPSEACH, ZAUTHORSEPSTHREESEPSTHREESEPSEACH, QAUTHORSEPSTHREESEPSTHREESEPSLAST, XAUTHORSEPSTHREESEPSTHREESEPSLAST, YAUTHORSEPSTHREESEPSTHREESEPSLAST, ZAUTHORSEPSTHREESEPSTHREESEPSLAST, QAUTHORNAMESNAMEFIRSTNAMEORDER, XAUTHORNAMESNAMEFIRSTNAMEORDER, YAUTHORNAMESNAMEFIRSTNAMEORDER, ZAUTHORNAMESNAMEFIRSTNAMEORDER, QAUTHORNAMESNAMEFIRSTINITIALSTYLE, XAUTHORNAMESNAMEFIRSTINITIALSTYLE, YAUTHORNAMESNAMEFIRSTINITIALSTYLE, ZAUTHORNAMESNAMEFIRSTINITIALSTYLE, QAUTHORNAMESNAMEFIRSTUPPERCASE, XAUTHORNAMESNAMEFIRSTUPPERCASE, YAUTHORNAMESNAMEFIRSTUPPERCASE, ZAUTHORNAMESNAMEFIRSTUPPERCASE, QAUTHORNAMESNAMEOTHERNAMEORDER, XAUTHORNAMESNAMEOTHERNAMEORDER, YAUTHORNAMESNAMEOTHERNAMEORDER, ZAUTHORNAMESNAMEOTHERNAMEORDER, QAUTHORNAMESNAMEOTHERINITIALSTYLE, XAUTHORNAMESNAMEOTHERINITIALSTYLE, YAUTHORNAMESNAMEOTHERINITIALSTYLE, ZAUTHORNAMESNAMEOTHERINITIALSTYLE, QAUTHORNAMESNAMEOTHERUPPERCASE, XAUTHORNAMESNAMEOTHERUPPERCASE, YAUTHORNAMESNAMEOTHERUPPERCASE, ZAUTHORNAMESNAMEOTHERUPPERCASE, QTEXTTEXTSINGLEPRECEEDING, XTEXTTEXTSINGLEPRECEEDING, YTEXTTEXTSINGLEPRECEEDING, ZTEXTTEXTSINGLEPRECEEDING, QTEXTTEXTSINGLEFOLLOWING, XTEXTTEXTSINGLEFOLLOWING, YTEXTTEXTSINGLEFOLLOWING, ZTEXTTEXTSINGLEFOLLOWING, QTEXTTEXTMULTIPLEPRECEEDING, XTEXTTEXTMULTIPLEPRECEEDING, YTEXTTEXTMULTIPLEPRECEEDING, ZTEXTTEXTMULTIPLEPRECEEDING, QTEXTTEXTMULTIPLEFOLLOWING, XTEXTTEXTMULTIPLEFOLLOWING, YTEXTTEXTMULTIPLEFOLLOWING, ZTEXTTEXTMULTIPLEFOLLOWING, QTEXTEDTEXTSINGLEPRECEEDING, XTEXTEDTEXTSINGLEPRECEEDING, YTEXTEDTEXTSINGLEPRECEEDING, ZTEXTEDTEXTSINGLEPRECEEDING, QTEXTEDTEXTSINGLEFOLLOWING, XTEXTEDTEXTSINGLEFOLLOWING, YTEXTEDTEXTSINGLEFOLLOWING, ZTEXTEDTEXTSINGLEFOLLOWING, QTEXTEDTEXTMULTIPLEPRECEEDING, XTEXTEDTEXTMULTIPLEPRECEEDING, YTEXTEDTEXTMULTIPLEPRECEEDING, ZTEXTEDTEXTMULTIPLEPRECEEDING, QTEXTEDTEXTMULTIPLEFOLLOWING, XTEXTEDTEXTMULTIPLEFOLLOWING, YTEXTEDTEXTMULTIPLEFOLLOWING, ZTEXTEDTEXTMULTIPLEFOLLOWING, PUBDATEPRECEEDING, PUBDATEFOLLOWING, PUBDATEFORMAT, PUBDATESEQUENCE, PUBDATEMONTHFORMAT, PUBDATEDAYFORMAT, PUBDATEYEARFORMAT, PUBDATEPADLEADINGZERO, PUBDATESTYLE, PUBDATESECPRECEEDING, PUBDATESECFOLLOWING, PUBDATESECFORMAT, PUBDATESECSEQUENCE, PUBDATESECMONTHFORMAT, PUBDATESECDAYFORMAT, PUBDATESECYEARFORMAT, PUBDATESECPADLEADINGZERO, PUBDATESECSTYLE, PUBDATEALLPRECEEDING, PUBDATEALLFOLLOWING, PUBDATEALLFORMAT, PUBDATEALLSEQUENCE, PUBDATEALLMONTHFORMAT, PUBDATEALLDAYFORMAT, PUBDATEALLYEARFORMAT, PUBDATEALLPADLEADINGZERO, PUBDATEALLSTYLE, TITLEPRECEEDING, TITLEFOLLOWING, TITLECASE, TITLESTYLE, BOOKTITLEPRECEEDING, BOOKTITLEFOLLOWING, BOOKTITLECASE, BOOKTITLESTYLE, SERIESTITLEPRECEEDING, SERIESTITLEFOLLOWING, SERIESTITLECASE, SERIESTITLESTYLE, ALLTITLEPRECEEDING, ALLTITLEFOLLOWING, ALLTITLECASE, ALLTITLESTYLE, JOURNALNAMEPRECEEDING, JOURNALNAMEFOLLOWING, JOURNALNAMECASE, JOURNALNAMEDEFAULTTEXT, JOURNALNAMEALTERNATETEXT, JOURNALNAMEPUNCTUATION, JOURNALNAMESTYLE, VOLUMEPRECEEDING, VOLUMEFOLLOWING, VOLUMESTYLE, ISSUEPRECEEDING, ISSUEFOLLOWING, ISSUESTYLE, PAGESSTYLE, PAGESSINGLEPAGEPRECEEDING, PAGESSINGLEPAGEFOLLOWING, PAGESPAGERANGEPRECEEDING, PAGESPAGERANGEFOLLOWING, PAGESPAGERANGETYPE, PUBLISHERPRECEEDING, PUBLISHERFOLLOWING, PUBLISHERSTYLE, PUBPLACEPRECEEDING, PUBPLACEFOLLOWING, PUBPLACESTYLE, PAGESPRECEEDING, PAGESFOLLOWING, REFNUMBERPRECEEDING, REFNUMBERFOLLOWING, REFNUMBERSTYLE, PUBDATEFIRSTSEP, PUBDATESECONDSEP, PUBDATESECFIRSTSEP, PUBDATESECSECONDSEP, PUBDATEALLFIRSTSEP, PUBDATEALLSECONDSEP, PAGESPAGERANGERANGESEPARATOR, SERIALPRECEEDING, SERIALFOLLOWING, SERIALSTYLE, ADDRESSPRECEEDING, ADDRESSFOLLOWING, ADDRESSSTYLE, USERDEF1PRECEEDING, USERDEF1FOLLOWING, USERDEF1STYLE, USERDEF2PRECEEDING, USERDEF2FOLLOWING, USERDEF2STYLE, USERDEF3PRECEEDING, USERDEF3FOLLOWING, USERDEF3STYLE, USERDEF4PRECEEDING, USERDEF4FOLLOWING, USERDEF4STYLE, USERDEF5PRECEEDING, USERDEF5FOLLOWING, USERDEF5STYLE, NOTESPRECEEDING, NOTESFOLLOWING, NOTESSTYLE, ABSTRACTPRECEEDING, ABSTRACTFOLLOWING, ABSTRACTSTYLE, TYPEOFWORKPRECEEDING, TYPEOFWORKFOLLOWING, TYPEOFWORKSTYLE, AREAPRECEEDING, AREAFOLLOWING, AREASTYLE, OSTYPEPRECEEDING, OSTYPEFOLLOWING, OSTYPESTYLE, DEGREEPRECEEDING, DEGREEFOLLOWING, DEGREESTYLE, RUNNINGTIMEPRECEEDING, RUNNINGTIMEFOLLOWING, RUNNINGTIMESTYLE, CLASSCODEINTLPRECEEDING, CLASSCODEINTLFOLLOWING, CLASSCODEINTLSTYLE, CLASSCODEUSPRECEEDING, CLASSCODEUSFOLLOWING, CLASSCODEUSSTYLE, SENDEREMAILPRECEEDING, SENDEREMAILFOLLOWING, SENDEREMAILSTYLE, RECIPIENTEMAILPRECEEDING, RECIPIENTEMAILFOLLOWING, RECIPIENTEMAILSTYLE, MEDIATYPEPRECEEDING, MEDIATYPEFOLLOWING, MEDIATYPESTYLE, NUMVOLUMESPRECEEDING, NUMVOLUMESFOLLOWING, NUMVOLUMESSTYLE, EDITIONPRECEEDING, EDITIONFOLLOWING, EDITIONSTYLE, COMPUTERPRECEEDING, COMPUTERFOLLOWING, COMPUTERSTYLE, CONFERENCELOCATIONPRECEEDING, CONFERENCELOCATIONFOLLOWING, CONFERENCELOCATIONSTYLE, REGISTRYNUMPRECEEDING, REGISTRYNUMFOLLOWING, REGISTRYNUMSTYLE, CLASSIFICATIONPRECEEDING, CLASSIFICATIONFOLLOWING, CLASSIFICATIONSTYLE, SECTIONPRECEEDING, SECTIONFOLLOWING, SECTIONSTYLE, PAMPHLETNUMPRECEEDING, PAMPHLETNUMFOLLOWING, PAMPHLETNUMSTYLE, CHAPTERNUMPRECEEDING, CHAPTERNUMFOLLOWING, CHAPTERNUMSTYLE, LINK0PRECEEDING, LINK0FOLLOWING, LINK0STYLE, LINK1PRECEEDING, LINK1FOLLOWING, LINK1STYLE, LINK2PRECEEDING, LINK2FOLLOWING, LINK2STYLE, LINK3PRECEEDING, LINK3FOLLOWING, LINK3STYLE, LINK4PRECEEDING, LINK4FOLLOWING, LINK4STYLE, CITEKEYPRECEEDING, CITEKEYFOLLOWING, CITEKEYSTYLE from %s.REFSTYLE where PUBTYPE='GEN' and CITSTYLEID=%u", main_db, citstyle_id);
    }
    else {
      sprintf(sql_command, "SELECT ID, QSTYLE, XSTYLE, YSTYLE, ZSTYLE, QALTERNATESTYLE, XALTERNATESTYLE, YALTERNATESTYLE, ZALTERNATESTYLE, QALTERNATETEXT, XALTERNATETEXT, YALTERNATETEXT, ZALTERNATETEXT, QABBREVIATEFIRST, XABBREVIATEFIRST, YABBREVIATEFIRST, ZABBREVIATEFIRST, QABBREVIATESUBSEQ, XABBREVIATESUBSEQ, YABBREVIATESUBSEQ, ZABBREVIATESUBSEQ, QABBREVIATEFIRSTMAXAUTHOR, XABBREVIATEFIRSTMAXAUTHOR, YABBREVIATEFIRSTMAXAUTHOR, ZABBREVIATEFIRSTMAXAUTHOR, QABBREVIATESUBSEQMAXAUTHOR, XABBREVIATESUBSEQMAXAUTHOR, YABBREVIATESUBSEQMAXAUTHOR, ZABBREVIATESUBSEQMAXAUTHOR, QABBREVIATEFIRSTDISPLAYAUTHOR, XABBREVIATEFIRSTDISPLAYAUTHOR, YABBREVIATEFIRSTDISPLAYAUTHOR, ZABBREVIATEFIRSTDISPLAYAUTHOR, QABBREVIATESUBSEQDISPLAYAUTHOR, XABBREVIATESUBSEQDISPLAYAUTHOR, YABBREVIATESUBSEQDISPLAYAUTHOR, ZABBREVIATESUBSEQDISPLAYAUTHOR, QAEMPTY, XAEMPTY, YAEMPTY, ZAEMPTY, QASAME, XASAME, YASAME, ZASAME, QPRECEEDING, XPRECEEDING, YPRECEEDING, ZPRECEEDING, QFOLLOWING, XFOLLOWING, YFOLLOWING, ZFOLLOWING, QAUTHORSEPSTWOSEPS, XAUTHORSEPSTWOSEPS, YAUTHORSEPSTWOSEPS, ZAUTHORSEPSTWOSEPS, QAUTHORSEPSTHREESEPSTHREESEPSEACH, XAUTHORSEPSTHREESEPSTHREESEPSEACH, YAUTHORSEPSTHREESEPSTHREESEPSEACH, ZAUTHORSEPSTHREESEPSTHREESEPSEACH, QAUTHORSEPSTHREESEPSTHREESEPSLAST, XAUTHORSEPSTHREESEPSTHREESEPSLAST, YAUTHORSEPSTHREESEPSTHREESEPSLAST, ZAUTHORSEPSTHREESEPSTHREESEPSLAST, QAUTHORNAMESNAMEFIRSTNAMEORDER, XAUTHORNAMESNAMEFIRSTNAMEORDER, YAUTHORNAMESNAMEFIRSTNAMEORDER, ZAUTHORNAMESNAMEFIRSTNAMEORDER, QAUTHORNAMESNAMEFIRSTINITIALSTYLE, XAUTHORNAMESNAMEFIRSTINITIALSTYLE, YAUTHORNAMESNAMEFIRSTINITIALSTYLE, ZAUTHORNAMESNAMEFIRSTINITIALSTYLE, QAUTHORNAMESNAMEFIRSTUPPERCASE, XAUTHORNAMESNAMEFIRSTUPPERCASE, YAUTHORNAMESNAMEFIRSTUPPERCASE, ZAUTHORNAMESNAMEFIRSTUPPERCASE, QAUTHORNAMESNAMEOTHERNAMEORDER, XAUTHORNAMESNAMEOTHERNAMEORDER, YAUTHORNAMESNAMEOTHERNAMEORDER, ZAUTHORNAMESNAMEOTHERNAMEORDER, QAUTHORNAMESNAMEOTHERINITIALSTYLE, XAUTHORNAMESNAMEOTHERINITIALSTYLE, YAUTHORNAMESNAMEOTHERINITIALSTYLE, ZAUTHORNAMESNAMEOTHERINITIALSTYLE, QAUTHORNAMESNAMEOTHERUPPERCASE, XAUTHORNAMESNAMEOTHERUPPERCASE, YAUTHORNAMESNAMEOTHERUPPERCASE, ZAUTHORNAMESNAMEOTHERUPPERCASE, QTEXTTEXTSINGLEPRECEEDING, XTEXTTEXTSINGLEPRECEEDING, YTEXTTEXTSINGLEPRECEEDING, ZTEXTTEXTSINGLEPRECEEDING, QTEXTTEXTSINGLEFOLLOWING, XTEXTTEXTSINGLEFOLLOWING, YTEXTTEXTSINGLEFOLLOWING, ZTEXTTEXTSINGLEFOLLOWING, QTEXTTEXTMULTIPLEPRECEEDING, XTEXTTEXTMULTIPLEPRECEEDING, YTEXTTEXTMULTIPLEPRECEEDING, ZTEXTTEXTMULTIPLEPRECEEDING, QTEXTTEXTMULTIPLEFOLLOWING, XTEXTTEXTMULTIPLEFOLLOWING, YTEXTTEXTMULTIPLEFOLLOWING, ZTEXTTEXTMULTIPLEFOLLOWING, QTEXTEDTEXTSINGLEPRECEEDING, XTEXTEDTEXTSINGLEPRECEEDING, YTEXTEDTEXTSINGLEPRECEEDING, ZTEXTEDTEXTSINGLEPRECEEDING, QTEXTEDTEXTSINGLEFOLLOWING, XTEXTEDTEXTSINGLEFOLLOWING, YTEXTEDTEXTSINGLEFOLLOWING, ZTEXTEDTEXTSINGLEFOLLOWING, QTEXTEDTEXTMULTIPLEPRECEEDING, XTEXTEDTEXTMULTIPLEPRECEEDING, YTEXTEDTEXTMULTIPLEPRECEEDING, ZTEXTEDTEXTMULTIPLEPRECEEDING, QTEXTEDTEXTMULTIPLEFOLLOWING, XTEXTEDTEXTMULTIPLEFOLLOWING, YTEXTEDTEXTMULTIPLEFOLLOWING, ZTEXTEDTEXTMULTIPLEFOLLOWING, PUBDATEPRECEEDING, PUBDATEFOLLOWING, PUBDATEFORMAT, PUBDATESEQUENCE, PUBDATEMONTHFORMAT, PUBDATEDAYFORMAT, PUBDATEYEARFORMAT, PUBDATEPADLEADINGZERO, PUBDATESTYLE, PUBDATESECPRECEEDING, PUBDATESECFOLLOWING, PUBDATESECFORMAT, PUBDATESECSEQUENCE, PUBDATESECMONTHFORMAT, PUBDATESECDAYFORMAT, PUBDATESECYEARFORMAT, PUBDATESECPADLEADINGZERO, PUBDATESECSTYLE, PUBDATEALLPRECEEDING, PUBDATEALLFOLLOWING, PUBDATEALLFORMAT, PUBDATEALLSEQUENCE, PUBDATEALLMONTHFORMAT, PUBDATEALLDAYFORMAT, PUBDATEALLYEARFORMAT, PUBDATEALLPADLEADINGZERO, PUBDATEALLSTYLE, TITLEPRECEEDING, TITLEFOLLOWING, TITLECASE, TITLESTYLE, BOOKTITLEPRECEEDING, BOOKTITLEFOLLOWING, BOOKTITLECASE, BOOKTITLESTYLE, SERIESTITLEPRECEEDING, SERIESTITLEFOLLOWING, SERIESTITLECASE, SERIESTITLESTYLE, ALLTITLEPRECEEDING, ALLTITLEFOLLOWING, ALLTITLECASE, ALLTITLESTYLE, JOURNALNAMEPRECEEDING, JOURNALNAMEFOLLOWING, JOURNALNAMECASE, JOURNALNAMEDEFAULTTEXT, JOURNALNAMEALTERNATETEXT, JOURNALNAMEPUNCTUATION, JOURNALNAMESTYLE, VOLUMEPRECEEDING, VOLUMEFOLLOWING, VOLUMESTYLE, ISSUEPRECEEDING, ISSUEFOLLOWING, ISSUESTYLE, PAGESSTYLE, PAGESSINGLEPAGEPRECEEDING, PAGESSINGLEPAGEFOLLOWING, PAGESPAGERANGEPRECEEDING, PAGESPAGERANGEFOLLOWING, PAGESPAGERANGETYPE, PUBLISHERPRECEEDING, PUBLISHERFOLLOWING, PUBLISHERSTYLE, PUBPLACEPRECEEDING, PUBPLACEFOLLOWING, PUBPLACESTYLE, PAGESPRECEEDING, PAGESFOLLOWING, REFNUMBERPRECEEDING, REFNUMBERFOLLOWING, REFNUMBERSTYLE, PUBDATEFIRSTSEP, PUBDATESECONDSEP, PUBDATESECFIRSTSEP, PUBDATESECSECONDSEP, PUBDATEALLFIRSTSEP, PUBDATEALLSECONDSEP, PAGESPAGERANGERANGESEPARATOR, SERIALPRECEEDING, SERIALFOLLOWING, SERIALSTYLE, ADDRESSPRECEEDING, ADDRESSFOLLOWING, ADDRESSSTYLE, USERDEF1PRECEEDING, USERDEF1FOLLOWING, USERDEF1STYLE, USERDEF2PRECEEDING, USERDEF2FOLLOWING, USERDEF2STYLE, USERDEF3PRECEEDING, USERDEF3FOLLOWING, USERDEF3STYLE, USERDEF4PRECEEDING, USERDEF4FOLLOWING, USERDEF4STYLE, USERDEF5PRECEEDING, USERDEF5FOLLOWING, USERDEF5STYLE, NOTESPRECEEDING, NOTESFOLLOWING, NOTESSTYLE, ABSTRACTPRECEEDING, ABSTRACTFOLLOWING, ABSTRACTSTYLE, TYPEOFWORKPRECEEDING, TYPEOFWORKFOLLOWING, TYPEOFWORKSTYLE, AREAPRECEEDING, AREAFOLLOWING, AREASTYLE, OSTYPEPRECEEDING, OSTYPEFOLLOWING, OSTYPESTYLE, DEGREEPRECEEDING, DEGREEFOLLOWING, DEGREESTYLE, RUNNINGTIMEPRECEEDING, RUNNINGTIMEFOLLOWING, RUNNINGTIMESTYLE, CLASSCODEINTLPRECEEDING, CLASSCODEINTLFOLLOWING, CLASSCODEINTLSTYLE, CLASSCODEUSPRECEEDING, CLASSCODEUSFOLLOWING, CLASSCODEUSSTYLE, SENDEREMAILPRECEEDING, SENDEREMAILFOLLOWING, SENDEREMAILSTYLE, RECIPIENTEMAILPRECEEDING, RECIPIENTEMAILFOLLOWING, RECIPIENTEMAILSTYLE, MEDIATYPEPRECEEDING, MEDIATYPEFOLLOWING, MEDIATYPESTYLE, NUMVOLUMESPRECEEDING, NUMVOLUMESFOLLOWING, NUMVOLUMESSTYLE, EDITIONPRECEEDING, EDITIONFOLLOWING, EDITIONSTYLE, COMPUTERPRECEEDING, COMPUTERFOLLOWING, COMPUTERSTYLE, CONFERENCELOCATIONPRECEEDING, CONFERENCELOCATIONFOLLOWING, CONFERENCELOCATIONSTYLE, REGISTRYNUMPRECEEDING, REGISTRYNUMFOLLOWING, REGISTRYNUMSTYLE, CLASSIFICATIONPRECEEDING, CLASSIFICATIONFOLLOWING, CLASSIFICATIONSTYLE, SECTIONPRECEEDING, SECTIONFOLLOWING, SECTIONSTYLE, PAMPHLETNUMPRECEEDING, PAMPHLETNUMFOLLOWING, PAMPHLETNUMSTYLE, CHAPTERNUMPRECEEDING, CHAPTERNUMFOLLOWING, CHAPTERNUMSTYLE, LINK0PRECEEDING, LINK0FOLLOWING, LINK0STYLE, LINK1PRECEEDING, LINK1FOLLOWING, LINK1STYLE, LINK2PRECEEDING, LINK2FOLLOWING, LINK2STYLE, LINK3PRECEEDING, LINK3FOLLOWING, LINK3STYLE, LINK4PRECEEDING, LINK4FOLLOWING, LINK4STYLE, CITEKEYPRECEEDING, CITEKEYFOLLOWING, CITEKEYSTYLE from REFSTYLE where PUBTYPE='GEN' and CITSTYLEID=%u", citstyle_id);
    }

    LOG_PRINT(LOG_DEBUG, sql_command);
    dbi_style_res = dbi_conn_query(conn, sql_command);
    if (!dbi_style_res) {
      LOG_PRINT(LOG_WARNING, "CITSTYLE select failed");
      free(sql_command);
      return NULL;
    }

    if (dbi_result_next_row(dbi_style_res) == 0) {
      LOG_PRINT(LOG_WARNING, "no CITSTYLE found");
      dbi_result_free(dbi_style_res);
      dbi_style_res = NULL;
      free(sql_command);
      return NULL;
    }
  }

  return dbi_style_res;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  unload_style(): frees the memory used by load_style(). If no memory
                  was allocated previously this function will do
		  nothing instead of crash

  void unload_style has no return value

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
void unload_style(void) {
  if (dbi_style_res != NULL) {
    dbi_result_free(dbi_style_res);
    dbi_style_res = NULL;
  }
}












