st/code/sql/sql_update.c

200 lines
5.3 KiB
C
Raw Normal View History

2008-04-04 00:00:00 +00:00
/*
===========================================================================
Copyright (C) 2007 HermitWorks Entertainment Corporation
This file is part of 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/q_shared.h"
#include "../qcommon/qcommon.h"
#include "sql.h"
stmtInfo_t * sql_update_parse( sqlInfo_t * db, const char ** s )
{
updateInfo_t * update = sql_calloc_stmt( db, sizeof(updateInfo_t) );
columnInfo_t * c;
parseInfo_t pi = { 0 };
char * tableName;
update->stmt.type = SQL_UPDATE;
tableName = parse_temp( s );
if ( SWITCHSTRING( tableName ) == CS('o','r',0,0 ) ) {
parse_temp( s ); // INSERT
update->orinsert = 1;
tableName = parse_temp( s );
}
update->stmt.table = find_table( db, tableName );
#ifdef DEVELOPER
if ( !update->stmt.table ) {
Com_Error( ERR_FATAL, "table '%s' does not exist.\n\n%s\n", tableName, CURRENT_STMT );
}
#endif
// 'SET'
switch( SWITCHSTRING( parse_temp( s ) ) ) {
case CS('s','e','t',0): pi.flags = PARSE_ASSIGN_TO_COLUMN; break;
case CS('c','s',0,0): pi.flags = PARSE_ASSIGN_CS; break;
default:
ASSERT(0);
}
update->search.column = -1;
update->assignmentCount = 0;
pi.db = db;
pi.params = update->stmt.params;
pi.table = update->stmt.table;
do {
if ( pi.flags & PARSE_ASSIGN_TO_COLUMN ) {
char * n = parse_temp( s );
c = find_column( update->stmt.table, n );
#ifdef DEVELOPER
if ( !c ) {
Com_Error( ERR_FATAL, "cannot find column '%s' on table '%s'.\n", n, update->stmt.table->name );
}
#endif
parse_temp( s ); // '='
pi.column = c->num;
}
update->assignments[ update->assignmentCount++ ] = parse_expression( s, &pi );
} while ( pi.more );
pi.column = 0;
pi.flags = 0;
for ( ;; )
{
char * t = parse_temp(s);
if ( t[0] == '\0' )
break;
switch( SWITCHSTRING(t) )
{
case CS('w','h','e','r'): update->where_expr = parse_expression( s, &pi ); break;
case CS('l','i','m','i'): update->limit = parse_expression( s, &pi ); break;
case CS('o','f','f','s'): update->offset = parse_expression( s, &pi ); break;
case CS('s','e','a','r'):
{
columnInfo_t * c = find_column( update->stmt.table, parse_temp( s ) );
ASSERT( c );
update->search.column = c->num;
update->search.start = parse_expression( s, &pi );
if ( pi.more )
update->search.end = parse_expression( s, &pi );
} break;
case CS('d','e','s','c'):
{
update->search.descending = 1;
} break;
}
}
return &update->stmt;
}
int sql_update_work( sqlInfo_t * db, updateInfo_t * update )
{
int i;
cellInfo_t * rows[ 512 ];
int modified[ 512 ];
int limit, offset;
stmtInfo_t * stmt = &update->stmt;
stmtType_t op;
// setup bounds
if ( update->limit ) {
limit = sql_eval( db, update->limit, stmt->table, 0,0,0, stmt->params, 0 ).integer;
limit = min( lengthof( rows ), limit );
} else
limit = lengthof( rows );
if ( update->offset ) {
offset = sql_eval( db, update->offset, stmt->table, 0,0,0, stmt->params, 0 ).integer;
} else
offset = 0;
update->rows_updated = sql_eval_search_and_where( db, &update->search, update->where_expr, stmt->table, stmt->params, rows, limit, offset );
// check to see if this update is actually an insert
if ( update->rows_updated == 0 && update->orinsert ) {
rows[ 0 ] = sql_insert_begin( db, stmt->table );
update->rows_updated = 1;
op = SQL_INSERT;
} else {
op = SQL_UPDATE;
}
// modify the rows
for ( i=0; i<update->rows_updated; i++ )
{
int j;
stmt->table->modified = 0;
for ( j=0; j<update->assignmentCount; j++ ) {
sql_eval( db, update->assignments[ j ], stmt->table, rows[ i ],i,update->rows_updated, stmt->params, 0 );
}
if ( op == SQL_UPDATE ) {
modified[ i ] = stmt->table->modified;
}
}
// make callbacks
if ( op == SQL_UPDATE ) {
if ( update->rows_updated ) {
stmt->table->last_changed++;
if ( db->update_trigger ) {
for ( i=0; i<update->rows_updated; i++ ) {
// don't send update to clients if the row actually hasn't been modified.
// !! this is turned off right now because this command is not gaurenteed to make it
// across to the client. the game only works because the commands that fail to make
// it across must some how be sent again later.
if( modified[ i ] )
{
db->update_trigger( db, stmt->table, (rows[ i ] - stmt->table->rows) / stmt->table->column_count );
}
}
}
}
} else {
sql_insert_done( db, stmt->table );
}
return 1;
}