/*
** 2001 September 15
**
** The author disclaims copyright to this source code.  In place of
** a legal notice, here is a blessing:
**
**    May you do good and not evil.
**    May you find forgiveness for yourself and forgive others.
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This header file defines the interface that the Nsqlc library
** presents to client programs.
**
** @(#) $Id: nsqlc.h,v 1.3 2004/02/12 23:05:37 pb Exp $
*/
#ifndef _NSQLC_H_
#define _NSQLC_H_
#include <stdarg.h>     /* Needed for the definition of va_list */

/*
** The version of the Nsqlc library.
*/
#define NSQLC_VERSION         "2.7.2"

/*
** Make sure we can call this stuff from C++.
*/
#ifdef __cplusplus
extern "C" {
#endif

/*
** The version string is also compiled into the library so that a program
** can check to make sure that the lib*.a file and the *.h file are from
** the same version.
*/
extern const char nsqlc_version[];

/*
** The NSQLC_UTF8 macro is defined if the library expects to see
** UTF-8 encoded data.  The NSQLC_ISO8859 macro is defined if the
** iso8859 encoded should be used.
*/
#define NSQLC_ISO8859 1

/*
** The following constant holds one of two strings, "UTF-8" or "iso8859",
** depending on which character encoding the Nsqlc library expects to
** see.  The character encoding makes a difference for the LIKE and GLOB
** operators and for the LENGTH() and SUBSTR() functions.
*/
extern const char nsqlc_encoding[];

/*
** Each open nsqlc database is represented by an instance of the
** following opaque structure.
*/
typedef struct nsqlc nsqlc;

/*
** A function to open a new nsqlc database.  
**
** If the database does not exist and mode indicates write
** permission, then a new database is created.  If the database
** does not exist and mode does not indicate write permission,
** then the open fails, an error message generated (if errmsg!=0)
** and the function returns 0.
** 
** If mode does not indicates user write permission, then the 
** database is opened read-only.
**
** The Truth:  As currently implemented, all databases are opened
** for writing all the time.  Maybe someday we will provide the
** ability to open a database readonly.  The mode parameters is
** provide in anticipation of that enhancement.
*/
nsqlc *nsqlc_open(const char *database, int mode, char **errmsg);
nsqlc *nsqlc_open_ssh(const char *database, int mode, char **errmsg);

/*
** A function to close the database.
**
** Call this function with a pointer to a structure that was previously
** returned from nsqlc_open() and the corresponding database will by closed.
*/
void nsqlc_close(nsqlc *);

/*
** The type for a callback function.
*/
typedef int (*nsqlc_callback)(void*,int,char**, char**);

/*
** A function to executes one or more statements of SQL.
**
** If one or more of the SQL statements are queries, then
** the callback function specified by the 3rd parameter is
** invoked once for each row of the query result.  This callback
** should normally return 0.  If the callback returns a non-zero
** value then the query is aborted, all subsequent SQL statements
** are skipped and the nsqlc_exec() function returns the NSQLC_ABORT.
**
** The 4th parameter is an arbitrary pointer that is passed
** to the callback function as its first parameter.
**
** The 2nd parameter to the callback function is the number of
** columns in the query result.  The 3rd parameter to the callback
** is an array of strings holding the values for each column.
** The 4th parameter to the callback is an array of strings holding
** the names of each column.
**
** The callback function may be NULL, even for queries.  A NULL
** callback is not an error.  It just means that no callback
** will be invoked.
**
** If an error occurs while parsing or evaluating the SQL (but
** not while executing the callback) then an appropriate error
** message is written into memory obtained from malloc() and
** *errmsg is made to point to that message.  The calling function
** is responsible for freeing the memory that holds the error
** message.  If errmsg==NULL, then no error message is ever written.
**
** The return value is is NSQLC_OK if there are no errors and
** some other return code if there is an error.  The particular
** return value depends on the type of error. 
**
** If the query could not be executed because a database file is
** locked or busy, then this function returns NSQLC_BUSY.  (This
** behavior can be modified somewhat using the nsqlc_busy_handler()
** and nsqlc_busy_timeout() functions below.)
*/
int nsqlc_exec(
  nsqlc*,                      /* An open database */
  const char *sql,              /* SQL to be executed */
  nsqlc_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg                 /* Error msg written here */
);

/*
** Return values for nsqlc_exec()
*/
#define NSQLC_OK           0   /* Successful result */
#define NSQLC_ERROR        1   /* SQL error or missing database */
#define NSQLC_INTERNAL     2   /* An internal logic error in Nsqlc */
#define NSQLC_PERM         3   /* Access permission denied */
#define NSQLC_ABORT        4   /* Callback routine requested an abort */
#define NSQLC_BUSY         5   /* The database file is locked */
#define NSQLC_LOCKED       6   /* A table in the database is locked */
#define NSQLC_NOMEM        7   /* A malloc() failed */
#define NSQLC_READONLY     8   /* Attempt to write a readonly database */
#define NSQLC_INTERRUPT    9   /* Operation terminated by nsqlc_interrupt() */
#define NSQLC_IOERR       10   /* Some kind of disk I/O error occurred */
#define NSQLC_CORRUPT     11   /* The database disk image is malformed */
#define NSQLC_NOTFOUND    12   /* (Internal Only) Table or record not found */
#define NSQLC_FULL        13   /* Insertion failed because database is full */
#define NSQLC_CANTOPEN    14   /* Unable to open the database file */
#define NSQLC_PROTOCOL    15   /* Database lock protocol error */
#define NSQLC_EMPTY       16   /* (Internal Only) Database table is empty */
#define NSQLC_SCHEMA      17   /* The database schema changed */
#define NSQLC_TOOBIG      18   /* Too much data for one row of a table */
#define NSQLC_CONSTRAINT  19   /* Abort due to contraint violation */
#define NSQLC_MISMATCH    20   /* Data type mismatch */
#define NSQLC_MISUSE      21   /* Library used incorrectly */

/*
** Each entry in an Nsqlc table has a unique integer key.  (The key is
** the value of the INTEGER PRIMARY KEY column if there is such a column,
** otherwise the key is generated at random.  The unique key is always
** available as the ROWID, OID, or _ROWID_ column.)  The following routine
** returns the integer key of the most recent insert in the database.
**
** This function is similar to the mysql_insert_id() function from MySQL.
*/
int nsqlc_last_insert_rowid(nsqlc*);

/*
** This function returns the number of database rows that were changed
** (or inserted or deleted) by the most recent called nsqlc_exec().
**
** All changes are counted, even if they were later undone by a
** ROLLBACK or ABORT.  Except, changes associated with creating and
** dropping tables are not counted.
**
** If a callback invokes nsqlc_exec() recursively, then the changes
** in the inner, recursive call are counted together with the changes
** in the outer call.
**
** Nsqlc implements the command "DELETE FROM table" without a WHERE clause
** by dropping and recreating the table.  (This is much faster than going
** through and deleting individual elements form the table.)  Because of
** this optimization, the change count for "DELETE FROM table" will be
** zero regardless of the number of elements that were originally in the
** table. To get an accurate count of the number of rows deleted, use
** "DELETE FROM table WHERE 1" instead.
*/
int nsqlc_changes(nsqlc*);

/* If the parameter to this routine is one of the return value constants
** defined above, then this routine returns a constant text string which
** descripts (in English) the meaning of the return value.
*/
const char *nsqlc_error_string(int);
#define nsqlcErrStr nsqlc_error_string  /* Legacy. Do not use in new code. */

/* This function causes any pending database operation to abort and
** return at its earliest opportunity.  This routine is typically
** called in response to a user action such as pressing "Cancel"
** or Ctrl-C where the user wants a long query operation to halt
** immediately.
*/
void nsqlc_interrupt(nsqlc*);


/* This function returns true if the given input string comprises
** one or more complete SQL statements.
**
** The algorithm is simple.  If the last token other than spaces
** and comments is a semicolon, then return true.  otherwise return
** false.
*/
int nsqlc_complete(const char *sql);

/*
** This routine identifies a callback function that is invoked
** whenever an attempt is made to open a database table that is
** currently locked by another process or thread.  If the busy callback
** is NULL, then nsqlc_exec() returns NSQLC_BUSY immediately if
** it finds a locked table.  If the busy callback is not NULL, then
** nsqlc_exec() invokes the callback with three arguments.  The
** second argument is the name of the locked table and the third
** argument is the number of times the table has been busy.  If the
** busy callback returns 0, then nsqlc_exec() immediately returns
** NSQLC_BUSY.  If the callback returns non-zero, then nsqlc_exec()
** tries to open the table again and the cycle repeats.
**
** The default busy callback is NULL.
**
** Nsqlc is re-entrant, so the busy handler may start a new query. 
** (It is not clear why anyone would every want to do this, but it
** is allowed, in theory.)  But the busy handler may not close the
** database.  Closing the database from a busy handler will delete 
** data structures out from under the executing query and will 
** probably result in a coredump.
*/
void nsqlc_busy_handler(nsqlc*, int(*)(void*,const char*,int), void*);

/*
** This routine sets a busy handler that sleeps for a while when a
** table is locked.  The handler will sleep multiple times until 
** at least "ms" milleseconds of sleeping have been done.  After
** "ms" milleseconds of sleeping, the handler returns 0 which
** causes nsqlc_exec() to return NSQLC_BUSY.
**
** Calling this routine with an argument less than or equal to zero
** turns off all busy handlers.
*/
void nsqlc_busy_timeout(nsqlc*, int ms);

/*
** This next routine is really just a wrapper around nsqlc_exec().
** Instead of invoking a user-supplied callback for each row of the
** result, this routine remembers each row of the result in memory
** obtained from malloc(), then returns all of the result after the
** query has finished. 
**
** As an example, suppose the query result where this table:
**
**        Name        | Age
**        -----------------------
**        Alice       | 43
**        Bob         | 28
**        Cindy       | 21
**
** If the 3rd argument were &azResult then after the function returns
** azResult will contain the following data:
**
**        azResult[0] = "Name";
**        azResult[1] = "Age";
**        azResult[2] = "Alice";
**        azResult[3] = "43";
**        azResult[4] = "Bob";
**        azResult[5] = "28";
**        azResult[6] = "Cindy";
**        azResult[7] = "21";
**
** Notice that there is an extra row of data containing the column
** headers.  But the *nrow return value is still 3.  *ncolumn is
** set to 2.  In general, the number of values inserted into azResult
** will be ((*nrow) + 1)*(*ncolumn).
**
** After the calling function has finished using the result, it should 
** pass the result data pointer to nsqlc_free_table() in order to 
** release the memory that was malloc-ed.  Because of the way the 
** malloc() happens, the calling function must not try to call 
** malloc() directly.  Only nsqlc_free_table() is able to release 
** the memory properly and safely.
**
** The return value of this routine is the same as from nsqlc_exec().
*/
int nsqlc_get_table(
  nsqlc*,               /* An open database */
  const char *sql,       /* SQL to be executed */
  char ***resultp,       /* Result written to a char *[]  that this points to */
  int *nrow,             /* Number of result rows written here */
  int *ncolumn,          /* Number of result columns written here */
  char **errmsg          /* Error msg written here */
);

/*
** Call this routine to free the memory that nsqlc_get_table() allocated.
*/
void nsqlc_free_table(char **result);

/*
** The following routines are wrappers around nsqlc_exec() and
** nsqlc_get_table().  The only difference between the routines that
** follow and the originals is that the second argument to the 
** routines that follow is really a printf()-style format
** string describing the SQL to be executed.  Arguments to the format
** string appear at the end of the argument list.
**
** All of the usual printf formatting options apply.  In addition, there
** is a "%q" option.  %q works like %s in that it substitutes a null-terminated
** string from the argument list.  But %q also doubles every '\'' character.
** %q is designed for use inside a string literal.  By doubling each '\''
** character it escapes that character and allows it to be inserted into
** the string.
**
** For example, so some string variable contains text as follows:
**
**      char *zText = "It's a happy day!";
**
** We can use this text in an SQL statement as follows:
**
**      nsqlc_exec_printf(db, "INSERT INTO table VALUES('%q')",
**          callback1, 0, 0, zText);
**
** Because the %q format string is used, the '\'' character in zText
** is escaped and the SQL generated is as follows:
**
**      INSERT INTO table1 VALUES('It''s a happy day!')
**
** This is correct.  Had we used %s instead of %q, the generated SQL
** would have looked like this:
**
**      INSERT INTO table1 VALUES('It's a happy day!');
**
** This second example is an SQL syntax error.  As a general rule you
** should always use %q instead of %s when inserting text into a string 
** literal.
*/
int nsqlc_exec_printf(
  nsqlc*,                      /* An open database */
  const char *sqlFormat,        /* printf-style format string for the SQL */
  nsqlc_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg,                /* Error msg written here */
  ...                           /* Arguments to the format string. */
);
int nsqlc_exec_vprintf(
  nsqlc*,                      /* An open database */
  const char *sqlFormat,        /* printf-style format string for the SQL */
  nsqlc_callback,              /* Callback function */
  void *,                       /* 1st argument to callback function */
  char **errmsg,                /* Error msg written here */
  va_list ap                    /* Arguments to the format string. */
);
int nsqlc_get_table_printf(
  nsqlc*,               /* An open database */
  const char *sqlFormat, /* printf-style format string for the SQL */
  char ***resultp,       /* Result written to a char *[]  that this points to */
  int *nrow,             /* Number of result rows written here */
  int *ncolumn,          /* Number of result columns written here */
  char **errmsg,         /* Error msg written here */
  ...                    /* Arguments to the format string */
);
int nsqlc_get_table_vprintf(
  nsqlc*,               /* An open database */
  const char *sqlFormat, /* printf-style format string for the SQL */
  char ***resultp,       /* Result written to a char *[]  that this points to */
  int *nrow,             /* Number of result rows written here */
  int *ncolumn,          /* Number of result columns written here */
  char **errmsg,         /* Error msg written here */
  va_list ap             /* Arguments to the format string */
);
char *nsqlc_mprintf(const char*,...);

/*
** Windows systems should call this routine to free memory that
** is returned in the in the errmsg parameter of nsqlc_open() when
** Nsqlc is a DLL.  For some reason, it does not work to call free()
** directly.
*/
void nsqlc_freemem(void *p);

/*
** Windows systems need functions to call to return the nsqlc_version
** and nsqlc_encoding strings.
*/
const char *nsqlc_libversion(void);
const char *nsqlc_libencoding(void);

/*
** A pointer to the following structure is used to communicate with
** the implementations of user-defined functions.
*/
typedef struct nsqlc_func nsqlc_func;

/*
** Use the following routines to create new user-defined functions.  See
** the documentation for details.
*/
int nsqlc_create_function(
  nsqlc*,                  /* Database where the new function is registered */
  const char *zName,        /* Name of the new function */
  int nArg,                 /* Number of arguments.  -1 means any number */
  void (*xFunc)(nsqlc_func*,int,const char**),  /* C code to implement */
  void *pUserData           /* Available via the nsqlc_user_data() call */
);
int nsqlc_create_aggregate(
  nsqlc*,                  /* Database where the new function is registered */
  const char *zName,        /* Name of the function */
  int nArg,                 /* Number of arguments */
  void (*xStep)(nsqlc_func*,int,const char**), /* Called for each row */
  void (*xFinalize)(nsqlc_func*),       /* Called once to get final result */
  void *pUserData           /* Available via the nsqlc_user_data() call */
);

/*
** Use the following routine to define the datatype returned by a
** user-defined function.  The second argument can be one of the
** constants NSQLC_NUMERIC, NSQLC_TEXT, or NSQLC_ARGS or it
** can be an integer greater than or equal to zero.  The datatype
** will be numeric or text (the only two types supported) if the
** argument is NSQLC_NUMERIC or NSQLC_TEXT.  If the argument is
** NSQLC_ARGS, then the datatype is numeric if any argument to the
** function is numeric and is text otherwise.  If the second argument
** is an integer, then the datatype of the result is the same as the
** parameter to the function that corresponds to that integer.
*/
int nsqlc_function_type(
  nsqlc *db,               /* The database there the function is registered */
  const char *zName,        /* Name of the function */
  int datatype              /* The datatype for this function */
);
#define NSQLC_NUMERIC     (-1)
#define NSQLC_TEXT        (-2)
#define NSQLC_ARGS        (-3)

/*
** The user function implementations call one of the following four routines
** in order to return their results.  The first parameter to each of these
** routines is a copy of the first argument to xFunc() or xFinialize().
** The second parameter to these routines is the result to be returned.
** A NULL can be passed as the second parameter to nsqlc_set_result_string()
** in order to return a NULL result.
**
** The 3rd argument to _string and _error is the number of characters to
** take from the string.  If this argument is negative, then all characters
** up to and including the first '\000' are used.
**
** The nsqlc_set_result_string() function allocates a buffer to hold the
** result and returns a pointer to this buffer.  The calling routine
** (that is, the implmentation of a user function) can alter the content
** of this buffer if desired.
*/
char *nsqlc_set_result_string(nsqlc_func*,const char*,int);
void nsqlc_set_result_int(nsqlc_func*,int);
void nsqlc_set_result_double(nsqlc_func*,double);
void nsqlc_set_result_error(nsqlc_func*,const char*,int);

/*
** The pUserData parameter to the nsqlc_create_function() and
** nsqlc_create_aggregate() routines used to register user functions
** is available to the implementation of the function using this
** call.
*/
void *nsqlc_user_data(nsqlc_func*);

/*
** Aggregate functions use the following routine to allocate
** a structure for storing their state.  The first time this routine
** is called for a particular aggregate, a new structure of size nBytes
** is allocated, zeroed, and returned.  On subsequent calls (for the
** same aggregate instance) the same buffer is returned.  The implementation
** of the aggregate can use the returned buffer to accumulate data.
**
** The buffer allocated is freed automatically be Nsqlc.
*/
void *nsqlc_aggregate_context(nsqlc_func*, int nBytes);

/*
** The next routine returns the number of calls to xStep for a particular
** aggregate function instance.  The current call to xStep counts so this
** routine always returns at least 1.
*/
int nsqlc_aggregate_count(nsqlc_func*);

/*
** Attempt to open the file named in the argument as the auxiliary database
** file.  The auxiliary database file is used to store TEMP tables.  But
** by using this API, it is possible to trick Nsqlc into opening two
** separate databases and acting on them as if they were one.
*/
int nsqlc_open_aux_file(nsqlc *db, const char *zName, char **pzErrMsg);

int nsqlc_get_time (nsqlc *ctx, time_t *t, char **err);

#ifdef __cplusplus
}  /* End of the 'extern "C"' block */
#endif

#endif /* _NSQLC_H_ */
