st/code/sql/sql.h

569 lines
16 KiB
C

/*
===========================================================================
Copyright (C) 2007 HermitWorks Entertainment Corporation
This file is part of the Space Trader source code.
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
===========================================================================
*/
#include "../qcommon/rand.h"
#ifndef ASSERT
#define ASSERT(x) assert(x)
#endif
#define MAX_COLUMNS_PER_TABLE 32
#define MAX_TABLES_PER_DB 48
#define MAX_STMTS_PER_DB 1024
#define MAX_CALL_STACK 8
#define SQL_CACHE_SIZE 65535
#ifdef DEVELOPER
extern const char * CURRENT_STMT;
#endif
//
// sql_strings.h
//
struct sql_strings;
typedef struct sql_strings sql_strings;
extern sql_strings* sql_str_init_strings ( unsigned int hash_size, int alloc_tag ); //initializes the string pool, set hash_size to an adequately sized prime for efficiency (should be at least a third of the number of strings you expect to intern at once)
extern const char* sql_str_intern ( sql_strings *strs, const char *str ); //add a string to the sql interned strings table - if it's already there it gets addref'd
extern const char* sql_str_intern_n ( sql_strings *strs, const char *str, unsigned int n ); //same as sql_str_intern, only stop reading str at n chars
extern const char* sql_str_is_interned ( sql_strings *strs, const char *str ); //if a string has been interned, return the interned pointer else return null - string is NOT addref'd
extern const char* sql_str_is_interned_n ( sql_strings *strs, const char *str, unsigned int n ); //same as sql_str_is_interned, only stop reading str at n chars
//
// sql_parse.c
//
typedef enum {
OP_END,
OP_NOP,
OP_ASSIGN_INT,
OP_LOGICAL_AND,
OP_LOGICAL_OR,
OP_BITWISE_AND,
OP_BITWISE_OR,
OP_SUBTRACT,
OP_ADD,
OP_DIVIDE,
OP_MULTIPLY,
OP_MODULUS,
OP_REMOVE,
OP_EQ,
OP_LE,
OP_NE,
OP_LSHIFT,
OP_LT,
OP_GE,
OP_GT,
OP_RSHIFT,
OP_NOT,
OP_NEGATE,
OP_UMINUS,
OP_PUSH_INTEGER,
OP_PUSH_INTEGER_PARAM,
OP_PUSH_INTEGER_GLOBAL,
OP_PUSH_STRING,
OP_PUSH_STRING_PARAM,
OP_PUSH_COLUMN_VAL,
OP_PUSH_GS,
OP_PUSH_GS_OFFSET,
OP_PUSH_PS_CLIENT,
OP_PUSH_PS_CLIENT_OFFSET,
OP_PUSH_COLUMN,
OP_ASSIGN_INT_TO_COLUMN,
OP_ASSIGN_STRING_TO_COLUMN,
OP_ASSIGN_CS_TO_ROW,
OP_CONCAT,
OP_FORMAT,
OP_ATOI,
OP_LIKE,
OP_MATCH,
OP_NOTLIKE,
OP_COLLAPSE,
OP_COUNT,
OP_SUM,
OP_MAX,
OP_MIN,
OP_ACCESS_TABLE,
OP_LOOKUP_I,
OP_LOOKUP_S,
OP_ACCESS_ROW_I,
OP_ACCESS_ROW_S,
OP_ROWINDEX,
OP_ROWNUMBER,
OP_ROWTOTAL,
OP_ROWCOUNT,
OP_IFTHENELSE,
OP_SHADER,
OP_SOUND,
OP_MODEL,
OP_PORTRAIT,
OP_RND,
OP_INT_MIN,
OP_INT_MAX,
OP_ABS,
OP_EVAL,
OP_PRINT,
OP_RUN,
OP_SYS_TIME,
OP_CVAR,
} op_t;
typedef union {
int i;
const char * s;
void * p;
} value_t;
typedef struct expr_s {
op_t op;
value_t v;
int n;
struct expr_s * left;
struct expr_s * right;
} expr_t;
typedef enum {
INVALID,
INTEGER,
STRING,
COLUMN,
ROW,
PARAMETER,
AGGREGATE,
} dataFormat_t;
expr_t * op ( expr_t * left, expr_t * right, op_t op );
expr_t * expr_i ( int i );
expr_t * expr_s ( const char * s, int n );
int gs_i ( const char* s );
int ps_i ( const char* s );
void compile ( expr_t * A, dataFormat_t rt );
int local ( const char* s, int n );
extern int parse ( const char ** data_p, char * buffer, int size, int * string_literal );
extern int parse_tofirstparam ( const char ** data_p );
extern int parse_tonextparam ( const char ** data_p );
extern int parse_tonextstatement ( const char ** data_p );
extern char * parse_keep ( const char ** s );
extern char * parse_temp ( const char ** s );
//
// sql.c
//
#define SQL_STMT_ALLOC 12*1024
typedef struct {
int top;
} sqlStack_t;
typedef union {
int integer;
const char *string;
} cellInfo_t;
typedef struct {
dataFormat_t format;
cellInfo_t payload;
} sqlData_t;
typedef struct {
int num;
dataFormat_t format;
short * index;
const char * name;
#ifdef DEVELOPER
struct {
const char * table;
const char * column;
} link;
#endif
} columnInfo_t;
#define SQL_TABLE_FROMSERVER 0x0001 // a table on the client db that is sync'd from the server
#define SQL_TABLE_CLIENTONLY 0x0002 // table that is only on the client
#define SQL_TABLE_SERVERONLY 0x0004 // table that is only on the server
#define SQL_TABLE_TEMPORARY 0x0008 // temporary, not written to disk
#define SQL_TABLE_BOTH 0x0010 // a table on both client and server but is not sync. they are expected to be the same!
typedef struct {
const char * name;
columnInfo_t columns[ MAX_COLUMNS_PER_TABLE ];
int column_count;
cellInfo_t * rows;
int row_count;
int row_total;
struct stmtInfo_t * sync;
int last_changed;
int last_indexed;
int flags;
int primary_column;
unsigned int modified; // bit field of columns just modified
} tableInfo_t;
typedef char * Expr;
typedef enum {
SQL_INSERT,
SQL_UPDATE,
SQL_CREATE,
SQL_SELECT,
SQL_DELETE,
SQL_FORMAT,
} stmtType_t;
typedef struct stmtInfo_t {
stmtType_t type; // type of statement
const char * src;
tableInfo_t * table;
sqlData_t params[ MAX_COLUMNS_PER_TABLE ]; // bound arguments '?'
int step;
} stmtInfo_t;
typedef struct {
int column;
Expr start;
Expr end;
int descending;
int unique;
} searchInfo_t;
typedef struct {
stmtInfo_t stmt;
Expr column_expr[ MAX_COLUMNS_PER_TABLE ];
dataFormat_t column_type[ MAX_COLUMNS_PER_TABLE ];
const char * column_name[ MAX_COLUMNS_PER_TABLE ];
int column_count;
Expr where_expr;
Expr limit;
Expr offset;
Expr random;
Expr sort;
int is_aggregate;
int entire_row;
searchInfo_t search;
struct {
cellInfo_t * result;
int row_count;
} cache;
} selectInfo_t;
typedef struct {
stmtType_t type; // type of statement
Expr print;
} formatInfo_t;
typedef struct {
stmtInfo_t stmt;
Expr values_expr[ MAX_COLUMNS_PER_TABLE ];
int values_count;
selectInfo_t * select;
char columns[ MAX_COLUMNS_PER_TABLE ];
} insertInfo_t;
typedef struct {
stmtInfo_t stmt;
Expr assignments[ MAX_COLUMNS_PER_TABLE ];
int assignmentCount;
Expr where_expr;
Expr limit;
Expr offset;
searchInfo_t search;
int rows_updated;
int orinsert;
} updateInfo_t;
typedef struct {
stmtInfo_t stmt;
Expr where_expr;
} deleteInfo_t;
struct sqlInfo_s;
typedef void (*sqltrigger_t)( struct sqlInfo_s * db, tableInfo_t * table, int row );
typedef struct sqlInfo_s {
tableInfo_t * tables [ MAX_TABLES_PER_DB ];
int table_count;
stmtInfo_t * stmts [ MAX_STMTS_PER_DB ];
int stmt_count;
stmtInfo_t * stmts_byindex[ MAX_STMTS_PER_DB ];
int stmts_byindex_count;
stmtInfo_t * callstack[ MAX_CALL_STACK ];
int pc;
sqltrigger_t insert_trigger;
sqltrigger_t update_trigger;
sqltrigger_t delete_trigger;
int * gs;
int * ps;
randState_t rand;
int memory_tag;
struct {
sqlStack_t * c; // current
sqlStack_t * p; // permanent
} stmt_buffer;
sql_strings *strings;
struct {
char * segment;
char * top;
char * buffer;
int size;
} cache;
// functions
qhandle_t (*shader) ( const char *name );
qhandle_t (*sound) ( const char *name );
qhandle_t (*portrait) ( const char * );
qhandle_t (*model) ( const char * );
int (*global_int) ( const char * );
#ifdef DEVELOPER
int ops;
#endif
char * create_filter;
} sqlInfo_t;
extern void * sql_cache_push ( sqlInfo_t * db, int n );
extern void sql_cache_pop ( sqlInfo_t * db, void * p );
// makes a copy of a string which can never be deleted
extern const char * sql_alloc_string ( sqlInfo_t * db, const char * s );
extern const char * sql_alloc_stringn ( sqlInfo_t * db, const char * s, int n );
// memory
extern void * sql_calloc ( sqlInfo_t * db, size_t size );
extern void * sql_alloc ( sqlInfo_t * db, size_t size );
extern void * sql_realloc ( sqlInfo_t * db, void * p, size_t size1, size_t size2 );
extern void sql_free ( sqlInfo_t * db, void * p );
extern void * sql_alloc_stmt ( sqlInfo_t * db, int n );
extern void * sql_calloc_stmt ( sqlInfo_t * db, int n );
extern tableInfo_t * find_table ( sqlInfo_t * db, const char * name );
extern columnInfo_t * find_column ( tableInfo_t * table, const char * name );
extern stmtInfo_t * find_stmt ( sqlInfo_t * db, const char * src );
extern void insert_stmt ( sqlInfo_t * db, stmtInfo_t * stmt );
extern void insert_table ( sqlInfo_t * db, tableInfo_t * table );
extern int sql_insert_work( sqlInfo_t * db, insertInfo_t * insert );
extern int sql_select_work( sqlInfo_t * db, selectInfo_t * select );
extern int sql_update_work( sqlInfo_t * db, updateInfo_t * update );
extern int sql_delete_work( sqlInfo_t * db, deleteInfo_t * delete );
extern const char * sql_format_work( sqlInfo_t * db, formatInfo_t * format );
extern stmtInfo_t * sql_parse ( sqlInfo_t * db, const char ** data_p, char * tmp );
extern stmtInfo_t * sql_create_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_select_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_insert_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_delete_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_update_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_format_parse( sqlInfo_t * db, const char ** data_p );
extern stmtInfo_t * sql_alter_parse ( sqlInfo_t * db, const char ** data_p );
extern void sql_create_index( sqlInfo_t * db, tableInfo_t * table, columnInfo_t * column );
extern void sql_insert_done ( sqlInfo_t * db, tableInfo_t * table );
extern void sql_update_done ( sqlInfo_t * db, tableInfo_t * table );
extern void sql_table_reindex( tableInfo_t * table );
extern cellInfo_t * sql_insert_begin( sqlInfo_t * db, tableInfo_t * table );
extern void sql_insert_done ( sqlInfo_t * db, tableInfo_t * table );
extern void sql_table_addcolumns( sqlInfo_t * db, tableInfo_t * table, const char ** s );
//
// sql_eval.c
//
#define PARSE_ALLOW_ASSIGNMENT 0x00001 // interprets '=' as assignment not equality
#define PARSE_ASSIGN_TO_COLUMN 0x00002 // adds ops to assign the final result to a column
#define PARSE_STRINGLITERAL 0x00004 // parse assuming input is a string literal
#define PARSE_ASSIGN_CS 0x00008 // parse as to assign a configstring to a row
typedef struct {
// in
sqlInfo_t * db;
tableInfo_t * table; // the table that is in scope
int arg; // the last argument that's been assigned to a '?'
int flags; // PARSE_* flags
int column;
// out
const char ** as; // optional name that the result is being called.
sqlData_t * params; // stores the parameter types i.e ?1 or $1
char * z; // the resulting expression
int n; // expression length
dataFormat_t rt; // expression return type
int more; // there's more expressions to parse
// temp
void * cache;
} parseInfo_t;
extern Expr parse_expression ( const char ** expression, // the regular expression to be parsed
parseInfo_t * pi
);
extern cellInfo_t sql_eval ( sqlInfo_t * db,
Expr expr, // the expression to be evaluated
tableInfo_t * table, // the table in scope
cellInfo_t * row, // the row in scope
int index, // the index of this row
int total, // the total rows in this statement
sqlData_t * params, // currently bound parameters
cellInfo_t * aggregate // aggregate storage
);
extern int sql_eval_where ( sqlInfo_t * db, Expr where_expr, tableInfo_t * table, sqlData_t * params, cellInfo_t ** rows, int limit, int offset );
extern int sql_eval_search_and_where ( sqlInfo_t * db, searchInfo_t * search, Expr where_expr, tableInfo_t * table, sqlData_t * params, cellInfo_t ** rows, int limit, int offset );
//
// sql_search.c
//
extern void * search ( const void * base, int count, int sizeOfElement, const void * key, int( *compare)(const void*, const void*) );
extern void insert_index_i ( short * index, int count, cellInfo_t * rows, int column_count, int column, short row_index );
extern void insert_index_s ( short * index, int count, cellInfo_t * rows, int column_count, int column, short row_index );
extern int search_index_i_first ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
extern int search_index_i_last ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
extern int search_index_s_first ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
extern int search_index_s_last ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
extern int search_index_i ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
extern int search_index_s ( short * index, int count, cellInfo_t * rows, int column_count, int column, cellInfo_t key );
//
// public
//
extern stmtInfo_t * sql_prepare ( sqlInfo_t * db, const char * src );
extern int sql_bind ( sqlInfo_t * db, intptr_t *args );
extern int sql_bindtext ( sqlInfo_t * db, int arg, const char * text );
extern int sql_bindint ( sqlInfo_t * db, int arg, int integer );
extern int sql_step ( sqlInfo_t * db );
extern int sql_exec ( sqlInfo_t * db, const char * src );
extern void sql_prompt ( sqlInfo_t * db, char * src );
extern int sql_columncount ( sqlInfo_t * db );
extern const char * sql_columnastext ( sqlInfo_t * db, int column );
extern int sql_columnasint ( sqlInfo_t * db, int column );
extern const char * sql_columnname ( sqlInfo_t * db, int column );
extern int sql_rowcount ( sqlInfo_t * db );
extern int sql_done ( sqlInfo_t * db );
extern int sql_expr ( sqlInfo_t * db, const char * src );
extern int sql_select ( sqlInfo_t * db, const char * src, char * segment, char * buffer, int size, ... );
// same as 'prepare' but in two steps
extern int sql_compile ( sqlInfo_t * db, const char * src );
extern const char * sql_run ( sqlInfo_t * db, int id );
extern void sql_error ( const char * msg );
extern void sql_reset ( sqlInfo_t * db, int memory_tag );
extern void sql_assign_triggers ( sqlInfo_t * db, sqltrigger_t insert, sqltrigger_t update, sqltrigger_t delete );
extern void sql_assign_gs ( sqlInfo_t * db, int * gs );
extern void sql_export ( const char * filename );
#ifdef DEVELOPER
extern void sql_save ( const char * filename );
#endif
extern sqlInfo_t * sql_getclientdb ( void );
extern sqlInfo_t * sql_getserverdb ( void );
extern sqlInfo_t * sql_getcommondb ( void );