merge android_branch->

This commit is contained in:
Eric House 2014-04-25 18:47:24 -07:00
commit f954b09391
7 changed files with 278 additions and 131 deletions

View file

@ -38,6 +38,7 @@ SRC = \
udpager.cpp \
udpqueue.cpp \
xwrelay.cpp \
querybld.cpp \
# STATIC ?= -static
GITINFO = gitversion.txt

View file

@ -43,11 +43,8 @@
static DBMgr* s_instance = NULL;
#define DELIM "\1"
#define MAX_NUM_PLAYERS 4
static void formatParams( char* paramValues[], int nParams, const char* fmt,
char* buf, int bufLen, ... );
static int here_less_seed( const char* seeds, int perDeviceSum,
unsigned short seed );
static void destr_function( void* conn );
@ -105,20 +102,21 @@ DBMgr::AddNew( const char* cookie, const char* connName, CookieID cid,
if ( !cookie ) cookie = "";
if ( !connName ) connName = "";
const char* command = "INSERT INTO " GAMES_TABLE
" (cid, room, connName, nTotal, lang, pub)"
" VALUES( $1, $2, $3, $4, $5, $6 )";
int nParams = 6;
char* paramValues[nParams];
char buf[512];
formatParams( paramValues, nParams,
"%d"DELIM"%s"DELIM"%s"DELIM"%d"DELIM"%d"DELIM"%s",
buf, sizeof(buf), cid, cookie, connName, nPlayersT,
langCode, isPublic?"TRUE":"FALSE" );
QueryBuilder qb;
qb.appendQueryf( "INSERT INTO " GAMES_TABLE
" (cid, room, connName, nTotal, lang, pub)"
" VALUES( $$, $$, $$, $$, $$, $$ )" )
.appendParam(cid)
.appendParam(cookie)
.appendParam(connName)
.appendParam(nPlayersT)
.appendParam(langCode)
.appendParam(isPublic?"TRUE":"FALSE" )
.finish();
PGresult* result = PQexecParams( getThreadConn(), command,
nParams, NULL,
paramValues,
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
qb.paramCount(), NULL,
qb.paramValues(),
NULL, NULL, 0 );
if ( PGRES_COMMAND_OK != PQresultStatus(result) ) {
logf( XW_LOGERROR, "PQexec=>%s;%s", PQresStatus(PQresultStatus(result)),
@ -271,28 +269,27 @@ DBMgr::SeenSeed( const char* cookie, unsigned short seed,
char* connNameBuf, int bufLen, int* nPlayersHP,
CookieID* cid )
{
int nParams = 5;
char* paramValues[nParams];
char buf[512];
formatParams( paramValues, nParams,
"%s"DELIM"%d"DELIM"%d"DELIM"%d"DELIM"%s", buf, sizeof(buf),
cookie, langCode, nPlayersT, seed,
wantsPublic?"TRUE":"FALSE" );
QueryBuilder qb;
qb.appendQueryf( "SELECT cid, connName, seeds, sum_array(nPerDevice) FROM "
GAMES_TABLE
" WHERE NOT dead"
" AND room ILIKE $$"
" AND lang = $$"
" AND nTotal = $$"
" AND $$ = ANY(seeds)"
" AND $$ = pub"
" ORDER BY ctime DESC"
" LIMIT 1")
.appendParam(cookie)
.appendParam(langCode)
.appendParam(nPlayersT)
.appendParam(seed)
.appendParam(wantsPublic?"TRUE":"FALSE" )
.finish();
const char* cmd = "SELECT cid, connName, seeds, sum_array(nPerDevice) FROM "
GAMES_TABLE
" WHERE NOT dead"
" AND room ILIKE $1"
" AND lang = $2"
" AND nTotal = $3"
" AND $4 = ANY(seeds)"
" AND $5 = pub"
" ORDER BY ctime DESC"
" LIMIT 1";
PGresult* result = PQexecParams( getThreadConn(), cmd,
nParams, NULL,
paramValues,
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
qb.paramCount(), NULL,
qb.paramValues(),
NULL, NULL, 0 );
bool found = 1 == PQntuples( result );
if ( found ) {
@ -312,31 +309,28 @@ DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH,
bool wantsPublic, char* connNameBuf, int bufLen,
int* nPlayersHP )
{
CookieID cid = 0;
QueryBuilder qb;
qb.appendQueryf("SELECT cid, connName, sum_array(nPerDevice) FROM "
GAMES_TABLE
" WHERE NOT dead"
" AND room ILIKE $$"
" AND lang = $$"
" AND nTotal = $$"
" AND $$ <= nTotal-sum_array(nPerDevice)"
" AND $$ = pub"
" LIMIT 1")
.appendParam(cookie)
.appendParam(lang)
.appendParam(nPlayersT)
.appendParam(nPlayersH)
.appendParam(wantsPublic?"TRUE":"FALSE" )
.finish();
int nParams = 5;
char* paramValues[nParams];
char buf[512];
formatParams( paramValues, nParams,
"%s"DELIM"%d"DELIM"%d"DELIM"%d"DELIM"%s", buf, sizeof(buf),
cookie, lang, nPlayersT, nPlayersH, wantsPublic?"TRUE":"FALSE" );
/* NOTE: ILIKE, for case-insensitive comparison, is a postgres extension
to SQL. */
const char* cmd = "SELECT cid, connName, sum_array(nPerDevice) FROM "
GAMES_TABLE
" WHERE NOT dead"
" AND room ILIKE $1"
" AND lang = $2"
" AND nTotal = $3"
" AND $4 <= nTotal-sum_array(nPerDevice)"
" AND $5 = pub"
" LIMIT 1";
PGresult* result = PQexecParams( getThreadConn(), cmd,
nParams, NULL,
paramValues,
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
qb.paramCount(), NULL,
qb.paramValues(),
NULL, NULL, 0 );
CookieID cid = 0;
if ( 1 == PQntuples( result ) ) {
cid = atoi( PQgetvalue( result, 0, 0 ) );
snprintf( connNameBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
@ -396,14 +390,21 @@ DBMgr::RegisterDevice( const DevID* host, int clientVersion,
devID = (DevIDRelay)random();
} while ( DEVID_NONE == devID );
StrWPF query;
query.catf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
" devids[1], clntVers, versdesc, model, osvers)"
" VALUES( %d, %d, '%s', %d, '%s', '%s', '%s' )",
devID, host->m_devIDType, devidStr, clientVersion,
desc, model, osVers );
logf( XW_LOGINFO, "%s: %s", __func__, query.c_str() );
success = execSql( query );
QueryBuilder qb;
qb.appendQueryf( "INSERT INTO " DEVICES_TABLE " (id, devTypes[1],"
" devids[1], clntVers, versdesc, model, osvers)"
" VALUES($$, $$, $$, $$, $$, $$, $$)" );
qb.appendParam( devID )
.appendParam( host->m_devIDType )
.appendParam( devidStr )
.appendParam( clientVersion )
.appendParam( desc )
.appendParam( model )
.appendParam( osVers )
.finish();
success = execParams( qb );
}
}
return devID;
@ -420,15 +421,17 @@ DBMgr::ReregisterDevice( DevIDRelay relayID, const DevID* host,
const char* const desc, int clientVersion,
const char* const model, const char* const osVers )
{
// First update the existing
StrWPF query;
query.catf( "UPDATE " DEVICES_TABLE " SET "
"devTypes = array_prepend( %d, devTypes), "
"devids = array_prepend('%s', devids), ",
host->m_devIDType, host->m_devIDString.c_str() );
QueryBuilder qb;
qb.appendQueryf( "UPDATE " DEVICES_TABLE " SET "
"devTypes = array_prepend($$, devTypes), "
"devids = array_prepend($$, devids), " )
formatUpdate( query, true, desc, clientVersion, model, osVers, relayID );
execSql( query );
.appendParam( host->m_devIDType )
.appendParam( host->m_devIDString.c_str() );
formatUpdate( qb, true, desc, clientVersion, model, osVers, relayID );
qb.finish();
execParams( qb );
}
// Return true if the relayID exists in the DB already
@ -445,10 +448,11 @@ DBMgr::UpdateDevice( DevIDRelay relayID, const char* const desc,
}
if ( exists ) {
StrWPF query;
query.catf( "UPDATE " DEVICES_TABLE " SET " );
formatUpdate( query, false, desc, clientVersion, model, osVers, relayID );
execSql( query );
QueryBuilder qb;
qb.appendQueryf( "UPDATE " DEVICES_TABLE " SET " );
formatUpdate( qb, false, desc, clientVersion, model, osVers, relayID );
qb.finish();
execParams( qb );
}
return exists;
}
@ -460,26 +464,33 @@ DBMgr::UpdateDevice( DevIDRelay relayID )
}
void
DBMgr::formatUpdate( StrWPF& query, bool append, const char* const desc,
DBMgr::formatUpdate( QueryBuilder& qb,
bool append, const char* const desc,
int clientVersion, const char* const model,
const char* const osVers, DevIDRelay relayID )
{
if ( append ) {
query.catf( "mtimes=array_prepend('now', mtimes)" ); // FIXME: too many
qb.appendQueryf( "mtimes=array_prepend('now', mtimes)" ); // FIXME: too many
} else {
query.catf( "mtimes[1]='now'" );
qb.appendQueryf( "mtimes[1]='now'" );
}
if ( NULL != desc && '\0' != desc[0] ) {
query.catf( ", clntVers=%d, versDesc='%s'", clientVersion, desc );
qb.appendQueryf( ", clntVers=$$" )
.appendParam( clientVersion )
.appendQueryf( ", versDesc=$$" )
.appendParam( desc );
}
if ( NULL != model && '\0' != model[0] ) {
query.catf( ", model='%s'", model );
qb.appendQueryf( ", model=$$" )
.appendParam( model );
}
if ( NULL != osVers && '\0' != osVers[0] ) {
query.catf( ", osvers='%s'", osVers );
qb.appendQueryf( ", osvers=$$" )
.appendParam( osVers );
}
query.catf( " WHERE id = %d", relayID );
qb.appendQueryf( " WHERE id = $$" )
.appendParam( relayID );
}
HostID
@ -831,6 +842,22 @@ DBMgr::execSql( const char* const query )
return ok;
}
bool
DBMgr::execParams( QueryBuilder& qb )
{
PGresult* result = PQexecParams( getThreadConn(), qb.c_str(),
qb.paramCount(), NULL,
qb.paramValues(),
NULL, NULL, 0 );
bool success = PGRES_COMMAND_OK == PQresultStatus( result );
if ( !success ) {
logf( XW_LOGERROR, "PQexecParams(%s)=>%s;%s", qb.c_str(),
PQresStatus(PQresultStatus(result)),
PQresultErrorMessage(result) );
}
return success;
}
void
DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /* len 4 */
{
@ -1255,31 +1282,6 @@ void DBMgr::clearHasNoMessages( DevIDRelay devid )
assert( !hasNoMessages( devid ) );
}
static void
formatParams( char* paramValues[], int nParams, const char* fmt, char* buf,
int bufLen, ... )
{
va_list ap;
va_start( ap, bufLen );
int len = vsnprintf( buf, bufLen, fmt, ap );
assert( buf[len] == '\0' );
int pnum;
char* ptr = buf;
for ( pnum = 0; pnum < nParams; ++pnum ) {
paramValues[pnum] = ptr;
for ( ; *ptr != '\0' && *ptr != DELIM[0]; ++ptr ) {
// do nothing
assert( ptr < &buf[bufLen] );
}
// we've found an end
*ptr = '\0';
++ptr;
}
va_end(ap);
}
static int
here_less_seed( const char* seeds, int sumPerDevice, unsigned short seed )
{

View file

@ -32,6 +32,7 @@
#include "xwrelay_priv.h"
#include "devid.h"
#include "strwpf.h"
#include "querybld.h"
using namespace std;
@ -149,6 +150,7 @@ class DBMgr {
DBMgr();
bool execSql( const string& query );
bool execSql( const char* const query ); /* no-results query */
bool execParams( QueryBuilder& qb );
void readArray( const char* const connName, const char* column, int arr[] );
DevIDRelay getDevID( const char* connName, int hid );
DevIDRelay getDevID( const DevID* devID );
@ -160,7 +162,7 @@ class DBMgr {
bool nullConnnameOK );
int CountStoredMessages( const char* const connName, int hid );
bool UpdateDevice( DevIDRelay relayID );
void formatUpdate( StrWPF& query, bool append, const char* const desc,
void formatUpdate( QueryBuilder& qb, bool append, const char* const desc,
int clientVersion, const char* const model,
const char* const osVers, DevIDRelay relayID );

View file

@ -0,0 +1,78 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
*
* 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.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <stdarg.h>
#include "querybld.h"
#include "xwrelay_priv.h"
QueryBuilder&
QueryBuilder::appendQueryf( const char* fmt, ... )
{
bool done;
do {
va_list ap;
va_start( ap, fmt );
done = m_query.catf( fmt, ap );
va_end( ap );
} while ( !done );
return *this;
}
QueryBuilder&
QueryBuilder::appendParam( const char* value )
{
m_paramIndices.push_back( m_paramBuf.size() );
m_paramBuf.catf( "%s%c", value, '\0' );
return *this;
}
QueryBuilder&
QueryBuilder::appendParam( int value )
{
m_paramIndices.push_back( m_paramBuf.size() );
m_paramBuf.catf( "%d%c", value, '\0' );
return *this;
}
/* When done adding params, some of which contain $$, turn these into an order
* progression of $1, $2 .. $9. Note assumption that we don't go above 9 since
*/
void
QueryBuilder::finish()
{
assert( 0 == m_paramValues.size() );
size_t ii;
const char* base = m_paramBuf.c_str();
for ( ii = 0; ii < m_paramIndices.size(); ++ii ) {
const char* ptr = m_paramIndices[ii] + base;
m_paramValues.push_back( ptr );
}
for ( size_t count = 0; ; ++count ) {
const char* str = m_query.c_str();
const char* ptr = strstr( str, "$$" );
if ( !ptr ) {
assert( count == m_paramIndices.size() );
break;
}
assert( count < 9 );
m_query[1 + ptr - str] = '1' + count;
}
}

47
xwords4/relay/querybld.h Normal file
View file

@ -0,0 +1,47 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
/*
* Copyright 2014 by Eric House (xwords@eehouse.org). All rights reserved.
*
* 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.
*
* 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _QUERYBLD_H_
#define _QUERYBLD_H_
#include <vector>
#include "strwpf.h"
using namespace std;
class QueryBuilder {
public:
QueryBuilder& appendQueryf( const char* fmt, ... );
QueryBuilder& appendParam( const char* value );
QueryBuilder& appendParam( int value );
void finish();
int paramCount() const { return m_paramValues.size(); }
const char* const* paramValues() const { return &m_paramValues[0]; }
const char* const c_str() const { return m_query.c_str(); }
private:
StrWPF m_query;
StrWPF m_paramBuf;
vector<size_t> m_paramIndices;
vector<const char*> m_paramValues;
};
#endif

View file

@ -27,26 +27,37 @@
/* From stack overflow: snprintf with an expanding buffer.
*/
bool
StrWPF::catf( const char* fmt, va_list ap )
{
bool success = false;
const int origsiz = size();
resize( origsiz + m_addsiz );
int len = vsnprintf( (char*)c_str() + origsiz, m_addsiz, fmt, ap );
if ( len >= m_addsiz ) { // needs more space
m_addsiz = len + 1;
resize( origsiz );
} else if ( -1 == len ) {
assert(0); // should be impossible
} else {
resize( origsiz + len );
m_addsiz = 100;
success = true;
}
return success;
}
void
StrWPF::catf( const char* fmt, ... )
{
const int origsiz = size();
int addsiz = 100;
va_list ap;
for ( ; ; ) {
resize( origsiz + addsiz );
bool done;
do {
va_list ap;
va_start( ap, fmt );
int len = vsnprintf( (char *)c_str() + origsiz, addsiz, fmt, ap );
done = catf( fmt, ap );
va_end( ap );
if ( len >= addsiz ) { // needs more space
addsiz = len + 1;
} else if ( -1 == len ) {
assert(0); // should be impossible
} else {
resize( origsiz + len );
break;
}
}
} while ( !done );
}

View file

@ -21,10 +21,16 @@
#define _STRWPF_H_
#include <string>
#include <stdarg.h>
class StrWPF : public std::string {
class StrWPF : public std::string {
public:
StrWPF() : m_addsiz(100){}
void catf( const char* fmt, ... );
bool catf( const char* fmt, va_list ap );
private:
int m_addsiz;
};
#endif