initial
This commit is contained in:
261
public/gcsdk/sqlaccess/columnset.h
Normal file
261
public/gcsdk/sqlaccess/columnset.h
Normal file
@@ -0,0 +1,261 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose: Sets of columns in queries
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef COLUMNSET_H
|
||||
#define COLUMNSET_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Sets of columns in queries
|
||||
//-----------------------------------------------------------------------------
|
||||
class CColumnSet
|
||||
{
|
||||
public:
|
||||
CColumnSet( const CRecordInfo *pRecordInfo );
|
||||
CColumnSet( const CRecordInfo *pRecordInfo, int nColumn );
|
||||
CColumnSet( const CColumnSet & rhs );
|
||||
CColumnSet & operator=( const CColumnSet & rhs );
|
||||
const CColumnSet operator+( const CColumnSet & rhs ) const;
|
||||
CColumnSet & operator+=( const CColumnSet & rhs );
|
||||
|
||||
bool BAddColumn( int nColumn );
|
||||
bool BRemoveColumn( int nColumn );
|
||||
bool IsSet( int nColumn ) const;
|
||||
bool IsEmpty() const { return m_vecColumns.Count() == 0;}
|
||||
|
||||
uint32 GetColumnCount() const;
|
||||
int GetColumn( int nIndex ) const;
|
||||
const CColumnInfo & GetColumnInfo( int nIndex ) const;
|
||||
|
||||
const CRecordInfo *GetRecordInfo() const { return m_pRecordInfo; }
|
||||
|
||||
// putting column sets in messages
|
||||
void AddToMessage( CGCMsgBase *pMsg ) const;
|
||||
bool BParseFromMessage( CGCMsgBase *pMsg );
|
||||
|
||||
void MakeEmpty();
|
||||
void MakeFull();
|
||||
void MakeInsertable();
|
||||
void MakeNoninsertable();
|
||||
void MakePrimaryKey();
|
||||
void MakeInverse( const CColumnSet & columnSet );
|
||||
|
||||
template< typename TSchClass >
|
||||
static CColumnSet Empty();
|
||||
template< typename TSchClass >
|
||||
static CColumnSet Full();
|
||||
template< typename TSchClass >
|
||||
static CColumnSet Insertable();
|
||||
template< typename TSchClass >
|
||||
static CColumnSet Noninsertable();
|
||||
template< typename TSchClass >
|
||||
static CColumnSet PrimaryKey();
|
||||
static CColumnSet Inverse( const CColumnSet & columnSet );
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName );
|
||||
#endif
|
||||
|
||||
private:
|
||||
CUtlVector<int> m_vecColumns;
|
||||
const CRecordInfo *m_pRecordInfo;
|
||||
};
|
||||
|
||||
// Usage notes:
|
||||
// The fields in a column set are order-dependent, and must match the order of the fields in
|
||||
// the query used to generate the data. The code that reads values doesn't do any fancy
|
||||
// name-matching and will copy values to incorrect locations silently if there is a
|
||||
// disagreement between the fields in the query and the fields in the column set.
|
||||
//
|
||||
// Examples:
|
||||
// // This is broken.
|
||||
// query = "SELECT * FROM Items";
|
||||
// columnSet = CSET_12_COL( CSchItem, individual_field_names );
|
||||
//
|
||||
// // This is fixed.
|
||||
// query = "SELECT * FROM Items";
|
||||
// columnSet = CSET_FULL( ... );
|
||||
|
||||
#define FOR_EACH_COLUMN_IN_SET( columnSet, iterName ) for( uint32 iterName = 0; iterName < (columnSet).GetColumnCount(); iterName++ )
|
||||
|
||||
#define CSET_EMPTY( schClass ) CColumnSet::Empty<schClass>()
|
||||
#define CSET_FULL( schClass ) CColumnSet::Full<schClass>()
|
||||
#define CSET_INSERTABLE( schClass ) CColumnSet::Insertable<schClass>()
|
||||
#define CSET_NONINSERTABLE( schClass ) CColumnSet::Noninsertable<schClass>()
|
||||
#define CSET_PK( schClass ) CColumnSet::PrimaryKey<schClass>()
|
||||
|
||||
#define CSET_1_COL( schClass, col1 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 )
|
||||
|
||||
#define CSET_2_COL( schClass, col1, col2 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 )
|
||||
|
||||
#define CSET_3_COL( schClass, col1, col2, col3 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 )
|
||||
|
||||
#define CSET_4_COL( schClass, col1, col2, col3, col4 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 )
|
||||
|
||||
#define CSET_5_COL( schClass, col1, col2, col3, col4, col5 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 )
|
||||
|
||||
#define CSET_6_COL( schClass, col1, col2, col3, col4, col5, col6 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 )
|
||||
|
||||
#define CSET_7_COL( schClass, col1, col2, col3, col4, col5, col6, col7 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 )
|
||||
|
||||
#define CSET_8_COL( schClass, col1, col2, col3, col4, col5, col6, col7, col8 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col8 )
|
||||
|
||||
#define CSET_9_COL( schClass, col1, col2, col3, col4, col5, col6, col7, col8, col9 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col8 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col9 )
|
||||
|
||||
#define CSET_10_COL( schClass, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col8 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col9 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col10 )
|
||||
|
||||
#define CSET_11_COL( schClass, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col8 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col9 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col10 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col11 )
|
||||
|
||||
#define CSET_12_COL( schClass, col1, col2, col3, col4, col5, col6, col7, col8, col9, col10, col11, col12 ) \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col1 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col2 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col3 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col4 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col5 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col6 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col7 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col8 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col9 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col10 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col11 ) + \
|
||||
CColumnSet( GSchemaFull().GetSchema( schClass::k_iTable ).GetRecordInfo(), schClass::col12 )
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns an empty Column Set for a schema class
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename TSchClass >
|
||||
CColumnSet CColumnSet::Empty()
|
||||
{
|
||||
CColumnSet set( GSchemaFull().GetSchema( TSchClass::k_iTable ).GetRecordInfo() );
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a Column Set for a schema class which contains every field
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename TSchClass >
|
||||
CColumnSet CColumnSet::Full()
|
||||
{
|
||||
CColumnSet set( GSchemaFull().GetSchema( TSchClass::k_iTable ).GetRecordInfo() );
|
||||
set.MakeFull();
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a Column Set for a schema class which contains every
|
||||
// insertable field
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename TSchClass >
|
||||
CColumnSet CColumnSet::Insertable()
|
||||
{
|
||||
CColumnSet set( GSchemaFull().GetSchema( TSchClass::k_iTable ).GetRecordInfo() );
|
||||
set.MakeInsertable();
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a Column Set for a schema class which contains every
|
||||
// noninsertable field
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename TSchClass >
|
||||
CColumnSet CColumnSet::Noninsertable()
|
||||
{
|
||||
CColumnSet set( GSchemaFull().GetSchema( TSchClass::k_iTable ).GetRecordInfo() );
|
||||
set.MakeNoninsertable();
|
||||
return set;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Returns a Column Set for a schema class which contains every
|
||||
// primary key field
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename TSchClass >
|
||||
CColumnSet CColumnSet::PrimaryKey()
|
||||
{
|
||||
CColumnSet set( GSchemaFull().GetSchema( TSchClass::k_iTable ).GetRecordInfo() );
|
||||
set.MakePrimaryKey();
|
||||
return set;
|
||||
}
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // COLUMNSET_H
|
||||
452
public/gcsdk/sqlaccess/record.h
Normal file
452
public/gcsdk/sqlaccess/record.h
Normal file
@@ -0,0 +1,452 @@
|
||||
//========= Copyright <20> 1996-2005, Valve Corporation, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GCRECORD_H
|
||||
#define GCRECORD_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "schema.h"
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
namespace GCSDK
|
||||
{
|
||||
#pragma pack( push, 1 )
|
||||
|
||||
class CRecordInfo;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VarFieldBlockInfo_t
|
||||
// Tracks a block of memory used to hold all the variable-length
|
||||
// fields for a record.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct VarFieldBlockInfo_t
|
||||
{
|
||||
union
|
||||
{
|
||||
// Take up 64-bits of space now even though
|
||||
// pointers are still 32 bits
|
||||
uint8* m_pubBlock;
|
||||
uint64 _unused;
|
||||
};
|
||||
uint32 m_cubBlock; // how much is in this block?
|
||||
uint32 m_cubBlockFree; // how much in this block is free?
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// VarField_t
|
||||
// Data format for a variable field entry in a DS record
|
||||
// For leaf code, is hidden inside a CVarField or CVarCharField
|
||||
//-----------------------------------------------------------------------------
|
||||
struct VarField_t
|
||||
{
|
||||
uint32 m_cubField; // Size of the field
|
||||
uint32 m_dubOffset; // Offset of the field within the block
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CVarField
|
||||
// Defines a class to encompass a variable-length field - opaque
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVarField : private VarField_t
|
||||
{
|
||||
public:
|
||||
friend class CRecordVar;
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CVarCharField
|
||||
// Defines a class to encompass a variable-length string field - opaque
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVarCharField : public CVarField
|
||||
{
|
||||
public:
|
||||
friend class CRecordVar;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CVarCharField
|
||||
// Defines a class to encompass a variable-length string field - opaque
|
||||
//-----------------------------------------------------------------------------
|
||||
class CVarBinaryField : public CVarField
|
||||
{
|
||||
public:
|
||||
friend class CRecordVar;
|
||||
};
|
||||
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
// fix the size of this just to be safe
|
||||
#pragma pack( push, 4 )
|
||||
|
||||
class CSchema;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CRecordBase
|
||||
// Defines a class which arbitrates access to a fixed-length record
|
||||
//
|
||||
// This is used as a base class for the CSchTable wrapper classes emitted
|
||||
// by the schema compiler when the involved table has no variable length data.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRecordBase
|
||||
{
|
||||
public:
|
||||
// These both allocate new space and COPY the record data into it
|
||||
CRecordBase( const CRecordBase &that );
|
||||
CRecordBase &operator=(const CRecordBase &that);
|
||||
|
||||
// Init from general memory
|
||||
int InitFromBytes( uint8 *pubRecord );
|
||||
|
||||
virtual ~CRecordBase();
|
||||
|
||||
// Use these when sending records over the wire
|
||||
uint32 CubSerialized();
|
||||
|
||||
virtual uint8 *PubRecordFixed();
|
||||
const uint8 *PubRecordFixed() const;
|
||||
uint32 CubRecordFixed() const;
|
||||
|
||||
virtual uint8 *PubRecordVarBlock();
|
||||
virtual const uint8 *PubRecordVarBlock() const;
|
||||
uint32 CubRecordVarBlock() const;
|
||||
bool BAssureRecordVarStorage( uint32 cVariableBytes );
|
||||
|
||||
// generic data accessors
|
||||
bool BGetField( int iField, uint8 **ppubData, uint32 *pcubField ) const;
|
||||
virtual bool BSetField( int iField, void * pvData, uint32 cubData );
|
||||
virtual void WipeField( int iField );
|
||||
|
||||
// data accessors
|
||||
const char * GetStringField( int iField, uint32 *pcubField );
|
||||
int GetInt( int iField );
|
||||
uint32 GetUint32( int iField );
|
||||
uint64 GetUint64( int iField );
|
||||
|
||||
// variable length data accessors
|
||||
// (not implemented by this class)
|
||||
virtual const char *ReadVarCharField( const CVarCharField &field ) const;
|
||||
virtual const uint8 *ReadVarDataField( const CVarField &field, uint32 *pcubField ) const;
|
||||
virtual bool SetVarCharField( CVarCharField &field, const char *pchString );
|
||||
virtual void SetVarDataField( CVarField &field, const void *pvData, uint32 cubData );
|
||||
|
||||
virtual const CSchema *GetPSchema() const
|
||||
{
|
||||
return const_cast<CRecordBase*>(this)->GetPSchema();
|
||||
}
|
||||
virtual CSchema *GetPSchema();
|
||||
const CRecordInfo *GetPRecordInfo() const;
|
||||
|
||||
// implemented by CSch-something derivatives
|
||||
virtual int GetITable() const = 0;
|
||||
|
||||
void RenderField( uint32 unColumn, int cchBuffer, char *pchBuffer ) const;
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
|
||||
static void ValidateStatics( CValidator &validator, const char *pchName );
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
protected:
|
||||
// copies the contents of the record. The assignement operator uses this internally
|
||||
virtual void Copy( const CRecordBase & that );
|
||||
|
||||
CSchema *GetPSchemaImpl();
|
||||
void Cleanup();
|
||||
bool BSetField( int iField, void *pvData, uint32 cubData, bool *pbRealloced );
|
||||
|
||||
|
||||
// ctor for derived classes, CSch*
|
||||
CRecordBase( ) { }
|
||||
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CRecordVar
|
||||
// Defines a class which arbitrates access to a variable-length record
|
||||
//
|
||||
// This is used as a base class for the CSchTable wrapper classes emitted
|
||||
// by the schema compiler when the involved table *does* have variable-length data
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRecordVar : public CRecordBase
|
||||
{
|
||||
public:
|
||||
CRecordVar( )
|
||||
{
|
||||
m_pSchema = NULL;
|
||||
m_nFlags = 0;
|
||||
}
|
||||
|
||||
virtual ~CRecordVar()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
virtual uint8* PubRecordFixed();
|
||||
const uint8 *PubRecordFixed() const;
|
||||
|
||||
virtual CSchema *GetPSchema()
|
||||
{
|
||||
return m_pSchema;
|
||||
}
|
||||
virtual const CSchema *GetPSchema() const
|
||||
{
|
||||
return m_pSchema;
|
||||
}
|
||||
|
||||
// Init from general memory
|
||||
int InitFromBytes( uint8 *pubRecord );
|
||||
|
||||
// generic data accessors
|
||||
virtual bool BSetField( int iField, void * pvData, uint32 cubData );
|
||||
virtual void WipeField( int iField );
|
||||
|
||||
// variable-length data accessors
|
||||
virtual const char *ReadVarCharField( const CVarCharField &field ) const;
|
||||
virtual const uint8 *ReadVarDataField( const CVarField &field, uint32 *pcubField ) const;
|
||||
virtual bool SetVarCharField( CVarCharField &field, const char *pchString );
|
||||
virtual void SetVarDataField( CVarField &field, const void *pvData, uint32 cubData );
|
||||
|
||||
// allocated fixed means we've got our own memory for the fixed record
|
||||
// allocated var block means we've allocated a block for the variable part of this record
|
||||
enum EFlags { k_EAllocatedFixed = 0x1, k_EAllocatedVarBlock = 0x2 };
|
||||
bool BFlagSet( int eFlag ) const;
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
protected:
|
||||
// copies the contents of the record. The assignement operator uses this internally
|
||||
virtual void Copy( const CRecordBase & that );
|
||||
|
||||
// initialization helper
|
||||
void DoInit()
|
||||
{
|
||||
m_pSchema = CRecordBase::GetPSchema();
|
||||
}
|
||||
|
||||
void SetFlag( int eFlag, bool bSet );
|
||||
|
||||
void Cleanup();
|
||||
CSchema *m_pSchema; // Corresponding Schema
|
||||
int m_nFlags; // Flags about the record memory allocations / location
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CRecordExternal
|
||||
// Defines a class which arbitrates access to a variable-length record
|
||||
//
|
||||
// This is used as an accessor for a polymorphic record. It can be used to
|
||||
// read CSchTable records when the type is unknown, manipulate stats records,
|
||||
// or touch data that isn't preallocated. Its use is relatively rare.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRecordExternal : public CRecordVar
|
||||
{
|
||||
public:
|
||||
CRecordExternal()
|
||||
{
|
||||
m_pubRecordFixedExternal = NULL;
|
||||
m_nFlags = 0;
|
||||
}
|
||||
|
||||
virtual ~CRecordExternal()
|
||||
{
|
||||
Cleanup();
|
||||
}
|
||||
|
||||
virtual uint8* PubRecordFixed();
|
||||
const uint8 *PubRecordFixed() const;
|
||||
|
||||
void DeSerialize( uint8 *pubData );
|
||||
|
||||
int GetITable() const
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void Init( CSchema *pSchema );
|
||||
int Init( CSchema *pSchema, uint8 *pubRecord, bool bTakeOwnership );
|
||||
|
||||
// test helpers
|
||||
void InitRecordRandom( uint32 unPrimaryIndex );
|
||||
void SetFieldRandom( int iField );
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
|
||||
protected:
|
||||
// copies the contents of the record. The assignement operator uses this internally
|
||||
virtual void Copy( const CRecordBase & that );
|
||||
|
||||
void Cleanup();
|
||||
|
||||
void DoInit()
|
||||
{
|
||||
m_pSchema = CRecordBase::GetPSchema();
|
||||
}
|
||||
|
||||
uint8 *m_pubRecordFixedExternal; // If the fixed record is not a part of this object,
|
||||
// this points to where it is
|
||||
|
||||
CSchema *GetPSchemaImpl();
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Accessors for variable length character data.
|
||||
// These goofy little macros implement some syntax sugar
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#define READ_VAR_CHAR_FIELD( record, field )\
|
||||
(record).ReadVarCharField( (record).field )
|
||||
|
||||
#define WRITE_VAR_CHAR_FIELD( record, field, text )\
|
||||
(record).SetVarCharField( (record).field, text )
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Template classes that get a LessFunc that sorts CRecordBases by a field
|
||||
// within them
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, int I, typename F>
|
||||
class CDefSchOps
|
||||
{
|
||||
public:
|
||||
static bool LessFunc( const T &lhs, const T &rhs )
|
||||
{
|
||||
// Check that the field number is valid
|
||||
COMPILE_TIME_ASSERT( I >= 0 && I < T::k_iFieldMax );
|
||||
|
||||
// Check to make sure this is a fixed field
|
||||
const Field_t &fieldInfo = lhs.GetPSchema()->GetField( I );
|
||||
Assert( !fieldInfo.BIsStringType() && !fieldInfo.BIsVariableLength() );
|
||||
if ( fieldInfo.BIsStringType() || fieldInfo.BIsVariableLength() )
|
||||
return false;
|
||||
|
||||
// Read the data and make sure the sizes are correct for the field type we expect
|
||||
uint8 *pubLhs;
|
||||
uint8 *pubRhs;
|
||||
bool bRet;
|
||||
uint32 cubRead;
|
||||
|
||||
bRet = lhs.BGetField( I, &pubLhs, &cubRead );
|
||||
Assert( bRet && cubRead == sizeof( F ) );
|
||||
if ( !bRet || cubRead != sizeof( F ) )
|
||||
return false;
|
||||
|
||||
bRet = rhs.BGetField( I, &pubRhs, &cubRead );
|
||||
Assert( bRet && cubRead == sizeof( F ) );
|
||||
if ( !bRet || cubRead != sizeof( F ) )
|
||||
return false;
|
||||
|
||||
// Finally do the comparison
|
||||
return ( *( (F *)pubLhs ) ) < ( *( (F *)pubRhs ) );
|
||||
}
|
||||
|
||||
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx )
|
||||
{
|
||||
return LessFunc( lhs, rhs );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#define DefSchLessFunc( RecordType, FieldIndex, FieldType ) CDefSchOps<RecordType, FieldIndex, FieldType>::LessFunc
|
||||
#define DefSchLessFuncCtx( RecordType, FieldIndex, FieldType ) CDefSchOps<RecordType, FieldIndex, FieldType>::LessFuncCtx
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Specializations for string fields
|
||||
//-----------------------------------------------------------------------------
|
||||
template <class T, int I>
|
||||
class CDefSchOps<T, I, char *>
|
||||
{
|
||||
public:
|
||||
static bool LessFunc( const T &lhs, const T &rhs )
|
||||
{
|
||||
// Check that the field number is valid
|
||||
COMPILE_TIME_ASSERT( I >= 0 && I < T::k_iFieldMax );
|
||||
|
||||
// Check to make sure this is indeed a string field
|
||||
Field_t &fieldInfo = lhs.GetPSchema()->GetField( I );
|
||||
Assert( fieldInfo.BIsStringType() );
|
||||
if ( !fieldInfo.BIsStringType() )
|
||||
return false;
|
||||
|
||||
// Read the data
|
||||
uint32 cubRead;
|
||||
const char *pchLhs = lhs.GetStringField( I, &cubRead );
|
||||
const char *pchRhs = rhs.GetStringField( I, &cubRead );
|
||||
|
||||
// Finally do the comparison
|
||||
return CDefOps<const char *>::LessFunc( lhs, rhs );
|
||||
}
|
||||
|
||||
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx )
|
||||
{
|
||||
return LessFunc( lhs, rhs );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T, int I>
|
||||
class CDefSchOps<T, I, const char *>
|
||||
{
|
||||
public:
|
||||
static bool LessFunc( const T &lhs, const T &rhs )
|
||||
{
|
||||
return CDefSchOps<T, I, char *>::LessFunc( lhs, rhs );
|
||||
}
|
||||
|
||||
static bool LessFuncCtx( const T &lhs, const T &rhs, void *pCtx )
|
||||
{
|
||||
return LessFunc( lhs, rhs );
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Provide a convenient object to pass around to represent a type
|
||||
// of record
|
||||
//-----------------------------------------------------------------------------
|
||||
class CRecordType
|
||||
{
|
||||
public:
|
||||
virtual int GetITable() const = 0;
|
||||
virtual CRecordBase *Create() const = 0;
|
||||
|
||||
CSchema *GetSchema() const;
|
||||
CRecordInfo *GetRecordInfo() const;
|
||||
protected:
|
||||
private:
|
||||
};
|
||||
|
||||
template <typename TRecord>
|
||||
class CRecordTypeConcrete: public CRecordType
|
||||
{
|
||||
public:
|
||||
virtual int GetITable() const { return TRecord::k_iTable; }
|
||||
virtual CRecordBase *Create() const { return new TRecord(); }
|
||||
};
|
||||
|
||||
#define RTYPE( recordClass ) CRecordTypeConcrete<recordClass>()
|
||||
|
||||
} // namespace GCSDK
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
|
||||
#endif // GCRECORD_H
|
||||
171
public/gcsdk/sqlaccess/recordinfo.h
Normal file
171
public/gcsdk/sqlaccess/recordinfo.h
Normal file
@@ -0,0 +1,171 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GCRECORDINFO_H
|
||||
#define GCRECORDINFO_H
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
|
||||
typedef CUtlMap<const char *,int> CMapIColumnInfo;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Information about a column in a record (table or result set)
|
||||
class CColumnInfo
|
||||
{
|
||||
public:
|
||||
CColumnInfo();
|
||||
~CColumnInfo() { }
|
||||
|
||||
void Set( const char *pchName, int nSQLColumn, EGCSQLType eGCSQLType, int cubFixedSize, int nColFlags, int cubMaxSize );
|
||||
const char *GetName() const { return m_rgchName; }
|
||||
int GetSQLColumn() const { return m_nSQLColumn; }
|
||||
EGCSQLType GetType() const { return m_eType; }
|
||||
int GetFixedSize() const { return m_cubFixedSize; }
|
||||
int GetMaxSize() const { return m_cchMaxSize; }
|
||||
int GetChecksum() const { Assert( m_bHaveChecksum ); return m_nChecksum; }
|
||||
bool BIsVariableLength() const;
|
||||
int GetColFlags() const { return m_nColFlags; }
|
||||
void GetColFlagDescription( char* pstrOut, int cubOutLength ) const;
|
||||
int GetConstraintColFlags() { return m_nColFlags & k_nColFlagAllConstraints; }
|
||||
void SetColFlagBits( int nColFlag );
|
||||
bool BIsIndexed() const { return 0 != ( m_nColFlags & k_nColFlagIndexed ); }
|
||||
bool BIsClustered() const { return 0 != ( m_nColFlags & k_nColFlagClustered ); }
|
||||
bool BIsUnique() const { return 0 != ( m_nColFlags & k_nColFlagUnique ); }
|
||||
bool BIsAutoIncrement() const { return 0 != ( m_nColFlags & k_nColFlagAutoIncrement ); }
|
||||
bool BIsPrimaryKey() const { return 0 != ( m_nColFlags & k_nColFlagPrimaryKey ); }
|
||||
bool BIsExplicitlyIndexed() const { return BIsIndexed() && !( BIsPrimaryKey() || BIsUnique() ); }
|
||||
bool BIsExplicitlyUnique() const { return BIsUnique() && !BIsPrimaryKey(); }
|
||||
bool BIsInsertable() const { return !BIsAutoIncrement(); }
|
||||
void CalculateChecksum();
|
||||
void ValidateColFlags() const;
|
||||
bool operator==( const CColumnInfo& refOther ) const;
|
||||
bool operator!=( const CColumnInfo& refOther ) const
|
||||
{
|
||||
return ! operator==( refOther );
|
||||
}
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName );
|
||||
#endif // DBGFLAG_VALIDATE
|
||||
private:
|
||||
CColumnInfo( CColumnInfo& ); // no copy constructor, disable default copy constructor
|
||||
CColumnInfo& operator = ( CColumnInfo& ); // no assignment operator, disable default assignment operator
|
||||
char m_rgchName[k_cSQLObjectNameMax+1];
|
||||
|
||||
EGCSQLType m_eType; // GC-based enum data type of this column
|
||||
int m_nColFlags; // flags for this column
|
||||
int m_nSQLColumn; // column # in SQL database to bind to, starts at 1.
|
||||
int m_cubFixedSize; // if fixed size, the fixed size in bytes; else 0
|
||||
int m_cchMaxSize; // if variable size, the maximum size; else 0
|
||||
int m_nChecksum; // checksum of this column info for quick comparisons
|
||||
bool m_bHaveChecksum; // have we calculated a checksum yet?
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Information about a record (table or result set)
|
||||
class CRecordInfo : public CRefCount
|
||||
{
|
||||
public:
|
||||
CRecordInfo();
|
||||
|
||||
void InitFromDSSchema( CSchema *pSchema );
|
||||
|
||||
void SetName( const char *pchName );
|
||||
const char *GetName() const { return m_rgchName; }
|
||||
void AddColumn( const char *pchName, int nSQLColumn, EGCSQLType eGCSQLType, int cubFixedSize, int nColFlags, int cubMaxSize );
|
||||
void SetAllColumnsAdded() { m_bAllColumnsAdded = true; }
|
||||
void PrepareForUse();
|
||||
int GetFixedSize() const { return m_cubFixedSize; }
|
||||
int GetNumColumns() const { return m_VecColumnInfo.Count(); }
|
||||
const CColumnInfo &GetColumnInfo( uint32 unColumn ) const { return m_VecColumnInfo[unColumn]; }
|
||||
CColumnInfo &GetColumnInfo( uint32 unColumn ) { return m_VecColumnInfo[unColumn]; }
|
||||
bool BFindColumnByName( const char *pchName, int *piColumn );
|
||||
bool BPreparedForUse() const { return m_bPreparedForUse; }
|
||||
void EnsureCapacity( int cColumns ) { m_VecColumnInfo.EnsureCapacity( cColumns ); }
|
||||
int GetChecksum();
|
||||
ESchemaCatalog GetESchemaCatalog() const { return m_eSchemaCatalog; }
|
||||
void SetESchemaCatalog( ESchemaCatalog e ) { m_eSchemaCatalog = e; }
|
||||
bool EqualTo( CRecordInfo* pOther );
|
||||
bool CompareIndexLists( CRecordInfo *pOther );
|
||||
bool CompareFKs( CRecordInfo *pOther );
|
||||
bool CompareFTSIndexLists( CRecordInfo *pOther ) const;
|
||||
EPrimaryKeyType GetPrimaryKeyType() const { return m_nHasPrimaryKey; }
|
||||
bool BHasPrimaryKey() { return GetPrimaryKeyType() != k_EPrimaryKeyTypeNone; }
|
||||
const FieldSet_t& GetPKFields() { Assert( BHasPrimaryKey()); return GetIndexFields( )[ m_iPKIndex ]; }
|
||||
const CUtlVector<FieldSet_t>& GetIndexFields() const { return m_VecIndexes; }
|
||||
int GetIndexFieldCount() const { return m_VecIndexes.Count(); }
|
||||
int GetPKIndex() const { return m_iPKIndex; }
|
||||
int AddIndex( const FieldSet_t& fieldSet );
|
||||
void GetIndexFieldList( CFmtStr1024 *pstr, int nIndents ) const;
|
||||
int GetTableID() const { return m_nTableID; }
|
||||
void SetTableID( int nTableID ) { m_nTableID = nTableID; }
|
||||
bool BHasIdentity() const;
|
||||
|
||||
// full-text index
|
||||
CUtlVector<int> & GetFTSFields() { return m_vecFTSFields; }
|
||||
bool BHasFTSIndex() const { return m_vecFTSFields.Count() > 0; }
|
||||
void AddFTSFields( CUtlVector< int > &refVecFields );
|
||||
int GetFullTextCatalogIndex() { return m_nFullTextCatalogIndex; }
|
||||
|
||||
// foreign keys
|
||||
void AddFK( const FKData_t &fkData );
|
||||
void GetFKListString( CFmtStr1024 *pstr, int nIndents );
|
||||
int GetFKCount();
|
||||
FKData_t &GetFKData( int iIndex );
|
||||
|
||||
|
||||
static CRecordInfo *Alloc();
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
static void ValidateStatics( CValidator &validator, const char *pchName );
|
||||
void Validate( CValidator &validator, const char *pchName );
|
||||
#endif //DBGFLAG_VALIDATE
|
||||
|
||||
|
||||
// note: destructor is private. This is a ref-counted object, private destructor ensures callers can't accidentally delete
|
||||
// directly, or declare on stack
|
||||
virtual ~CRecordInfo() { }
|
||||
|
||||
private:
|
||||
virtual void DestroyThis();
|
||||
void CalculateChecksum();
|
||||
void BuildColumnNameIndex();
|
||||
|
||||
char m_rgchName[k_cSQLObjectNameMax+1];
|
||||
int m_nTableID; // Object_ID if this table in SQL Server
|
||||
CUtlVector<CColumnInfo> m_VecColumnInfo; // Vector of columns in this record
|
||||
CMapIColumnInfo m_MapIColumnInfo; // Map of name->column index for quick lookup by name
|
||||
EPrimaryKeyType m_nHasPrimaryKey; // Does this table contain a column that is a primary key?
|
||||
int m_iPKIndex; // index info m_VecIndexes of our PK index; -1 if no PK
|
||||
CUtlVector<FieldSet_t> m_VecIndexes; // vector of all fields in all indexes
|
||||
int m_cubFixedSize; // Sum of data sizes for all fixed size columns
|
||||
bool m_bAllColumnsAdded; // Have all columns been added
|
||||
bool m_bPreparedForUse; // Have we finished being initialized?
|
||||
bool m_bHaveColumnNameIndex; // Have we created a column name index? (Only generated if someone asks.)
|
||||
bool m_bHaveChecksum; // Have we generated a checksum? (Only generated if someone asks.)
|
||||
int m_nChecksum; // checksum of this record info for quick comparisons - includes all columns
|
||||
ESchemaCatalog m_eSchemaCatalog; // what catalog owns this object?
|
||||
CUtlVector< int > m_vecFTSFields; // which fields have FTS indexing?
|
||||
int m_nFullTextCatalogIndex; // index of catalog for FTS index, if we get one
|
||||
CUtlVector<FKData_t> m_VecFKData; // vector of all FK relationships defined on this table
|
||||
|
||||
CThreadMutex m_Mutex;
|
||||
static CThreadSafeClassMemoryPool<CRecordInfo> sm_MemPoolRecordInfo;
|
||||
|
||||
#ifdef _DEBUG
|
||||
// validation tracking
|
||||
static CUtlRBTree<CRecordInfo *, int > sm_mapPMemPoolRecordInfo;
|
||||
static CThreadMutex sm_mutexMemPoolRecordInfo;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
int __cdecl CompareColumnInfo( const CColumnInfo *pColumnInfoLeft, const CColumnInfo *pColumnInfoRight );
|
||||
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // GCRECORDINFO_H
|
||||
591
public/gcsdk/sqlaccess/schema.h
Normal file
591
public/gcsdk/sqlaccess/schema.h
Normal file
@@ -0,0 +1,591 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GCSCHEMA_H
|
||||
#define GCSCHEMA_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
const int k_nColFlagIndexed = 0x0001; // this column is indexed.
|
||||
const int k_nColFlagUnique = 0x0002; // this column has a uniqueness constraint - creates implicit index
|
||||
const int k_nColFlagPrimaryKey = 0x0004; // this column has a primary key constraint - creates implicit uniqueness constraint & implicit index
|
||||
const int k_nColFlagAutoIncrement = 0x0008; // this column can have it's values created implicitly by the sql counter
|
||||
const int k_nColFlagClustered = 0x0010; // this column is clustered
|
||||
|
||||
const int k_nColFlagAllConstraints = k_nColFlagUnique | k_nColFlagPrimaryKey;
|
||||
|
||||
class CRecordInfo;
|
||||
struct VarFieldBlockInfo_t;
|
||||
struct VarFieldBlockInfo_t;
|
||||
struct Field_t;
|
||||
struct VarField_t;
|
||||
|
||||
// Function type for altering field types when converting schemas
|
||||
typedef void (* PfnAlterField_t )( void *pvDest, const void *pvSrc );
|
||||
|
||||
// EPrimaryKeyType
|
||||
// This shows if a table has a primary key and, if so, if it has multiple columns
|
||||
// or not.
|
||||
enum EPrimaryKeyType
|
||||
{
|
||||
k_EPrimaryKeyTypeNone = 0, // none at all
|
||||
k_EPrimaryKeyTypeSingle, // single-column primary key
|
||||
k_EPrimaryKeyTypeMulti, // multi-column primary key
|
||||
};
|
||||
|
||||
|
||||
// EWipePolicy
|
||||
// This tells us if a table is supposed to be wiped before all tests,
|
||||
// before all tests except stress tests, or not to be wiped before tests.
|
||||
enum EWipePolicy
|
||||
{
|
||||
k_EWipePolicyPreserveAlways = 0, // don't wipe table
|
||||
k_EWipePolicyPreserveForStress = 1, // preserve for stress tests, wipe before regular tests
|
||||
k_EWipePolicyWipeForAllTests = 2, // wipe table prior to all tests
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Field
|
||||
// This defines the schema of a single field in one of our tables.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct Field_t
|
||||
{
|
||||
bool BGetIntData( uint8 *pubRecord, uint64 *pulRet ) const;
|
||||
bool BGetFloatData( uint8 *pubRecord, float *fRet ) const;
|
||||
bool SetIntData( uint8 *pubRecord, uint64 ulValue ) const;
|
||||
// Not all fields are updated wholly at a time
|
||||
int CubFieldUpdateSize() const;
|
||||
// Handy helpers - complex fields like "rolling unique" are
|
||||
// still binary
|
||||
bool BIsStringType() const;
|
||||
|
||||
bool BIsVariableLength() const;
|
||||
|
||||
// Members that get serialized
|
||||
EGCSQLType m_EType; // Field type
|
||||
uint32 m_cubLength; // Length of the field in bytes
|
||||
uint32 m_cchMaxLength; // maximum length of the field in characters
|
||||
char m_rgchName[k_cSQLObjectNameMax]; // Human-readable name of this field
|
||||
char m_rgchSQLName[k_cSQLObjectNameMax]; // SQL name of this field
|
||||
|
||||
// Members that don't get serialized
|
||||
uint32 m_nColFlags; // k_nColFlag* bits for this field
|
||||
uint32 m_dubOffset; // Offset of this field from beginning of record
|
||||
};
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Information about a foreign key relationship defined on a table
|
||||
struct FKColumnRelation_t
|
||||
{
|
||||
char m_rgchCol[k_cSQLObjectNameMax+1];
|
||||
char m_rgchParentCol[k_cSQLObjectNameMax+1];
|
||||
|
||||
FKColumnRelation_t()
|
||||
{
|
||||
Q_memset( m_rgchCol, 0, Q_ARRAYSIZE( m_rgchCol ) );
|
||||
Q_memset( m_rgchParentCol, 0, Q_ARRAYSIZE( m_rgchParentCol ) );
|
||||
}
|
||||
|
||||
bool operator==( const FKColumnRelation_t &other ) const
|
||||
{
|
||||
if ( Q_stricmp( m_rgchCol, other.m_rgchCol ) )
|
||||
return false;
|
||||
if ( Q_stricmp( m_rgchParentCol, other.m_rgchParentCol ) )
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct FKData_t
|
||||
{
|
||||
char m_rgchName[k_cSQLObjectNameMax+1];
|
||||
char m_rgchParentTableName[k_cSQLObjectNameMax+1];
|
||||
CCopyableUtlVector<FKColumnRelation_t> m_VecColumnRelations;
|
||||
EForeignKeyAction m_eOnDeleteAction;
|
||||
EForeignKeyAction m_eOnUpdateAction;
|
||||
|
||||
FKData_t()
|
||||
{
|
||||
Q_memset( m_rgchName, 0, Q_ARRAYSIZE( m_rgchName ) );
|
||||
Q_memset( m_rgchParentTableName, 0, Q_ARRAYSIZE( m_rgchParentTableName ) );
|
||||
m_eOnDeleteAction = k_EForeignKeyActionNoAction;
|
||||
m_eOnUpdateAction = k_EForeignKeyActionNoAction;
|
||||
}
|
||||
|
||||
bool operator==( const FKData_t &other ) const
|
||||
{
|
||||
if ( Q_stricmp( m_rgchName, other.m_rgchName ) )
|
||||
return false;
|
||||
|
||||
if ( Q_stricmp( m_rgchParentTableName, other.m_rgchParentTableName ) )
|
||||
return false;
|
||||
|
||||
if ( m_eOnDeleteAction != other.m_eOnDeleteAction || m_eOnUpdateAction != other.m_eOnUpdateAction )
|
||||
return false;
|
||||
|
||||
FOR_EACH_VEC( m_VecColumnRelations, i )
|
||||
{
|
||||
bool bFoundInOther = false;
|
||||
const FKColumnRelation_t &cols = m_VecColumnRelations[i];
|
||||
|
||||
FOR_EACH_VEC( other.m_VecColumnRelations, j )
|
||||
{
|
||||
const FKColumnRelation_t &colsOther = other.m_VecColumnRelations[j];
|
||||
if ( cols == colsOther )
|
||||
{
|
||||
bFoundInOther = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !bFoundInOther )
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
// Validate our internal structures
|
||||
void Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
ValidateObj( m_VecColumnRelations );
|
||||
}
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
#pragma pack( push, 1 )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SerSchema
|
||||
// Defines the binary serialization format for a schema.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct SerSchema_t
|
||||
{
|
||||
uint32 m_cub; // Size of the whole schema (including header and fields)
|
||||
int32 m_iTable; // Our table's iTable
|
||||
char m_rgchName[k_cSQLObjectNameMax]; // Human-readable name of this table
|
||||
int16 m_cField; // # of fields in the schema (int16 for backward-compatibility reasons)
|
||||
int16 m_ETableGroup; // Our table's TableGroup (int16 for backward-compatibility reasons) - OBSOLETE
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SerField
|
||||
// Defines the binary serialization format for a field in a schema
|
||||
// Note that certain fields are missing from this because we only use serialized
|
||||
// schemas for schema mapping. Fields that only affect runtime behavior (like
|
||||
// indexing) are always defined by the intrinsic schema.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct SerField_t
|
||||
{
|
||||
int32 m_EType; // Field type
|
||||
uint32 m_cubLength; // Length of field data in bytes
|
||||
// For rolling fields, high 16 bits are the
|
||||
// size of each element
|
||||
|
||||
char m_rgchName[k_cSQLObjectNameMax];// Human-readable name of this field
|
||||
char m_rgchSQLName[k_cSQLObjectNameMax]; // SQL name of this field
|
||||
};
|
||||
|
||||
#pragma pack( pop )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Schema conversion instructions
|
||||
// These specify various operations that can be performed when converting
|
||||
// from one Schema to another.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct DeleteField_t
|
||||
{
|
||||
char m_rgchFieldName[k_cSQLObjectNameMax]; // Name of the field to delete
|
||||
};
|
||||
|
||||
struct RenameField_t
|
||||
{
|
||||
char m_rgchFieldNameOld[k_cSQLObjectNameMax]; // Rename a field with this name
|
||||
int m_iFieldDst; // to this field
|
||||
};
|
||||
|
||||
struct AlterField_t
|
||||
{
|
||||
char m_rgchFieldNameOld[k_cSQLObjectNameMax]; // Name of field in the old schema
|
||||
int m_iFieldDst; // iField of it in the new
|
||||
PfnAlterField_t m_pfnAlterFunc; // Function to translate the data
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// FieldSet_t describes a collection of fields in an index, as well as
|
||||
// attributes of the index itself
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class FieldSet_t
|
||||
{
|
||||
public:
|
||||
FieldSet_t( bool bUnique, bool bClustered, const CUtlVector<int>& vecFields, const char* pstrIndexName )
|
||||
: m_bClustered( bClustered ), m_bUnique( bUnique )
|
||||
{
|
||||
m_VecFields = vecFields;
|
||||
|
||||
// zero means to use the server default
|
||||
m_nFillFactor = 0;
|
||||
|
||||
// null name is allowed for primary keys
|
||||
if ( pstrIndexName != NULL )
|
||||
Q_strncpy( m_szIndexName, pstrIndexName, Q_ARRAYSIZE( m_szIndexName ) );
|
||||
else
|
||||
m_szIndexName[0] = 0;
|
||||
}
|
||||
|
||||
FieldSet_t( )
|
||||
{
|
||||
}
|
||||
|
||||
~FieldSet_t( )
|
||||
{
|
||||
}
|
||||
|
||||
FieldSet_t( const FieldSet_t &refOther )
|
||||
{
|
||||
DoAssignment( refOther );
|
||||
}
|
||||
|
||||
FieldSet_t& operator=( const FieldSet_t &refOther )
|
||||
{
|
||||
DoAssignment( refOther );
|
||||
return *this;
|
||||
}
|
||||
|
||||
void DoAssignment( const FieldSet_t &refOther )
|
||||
{
|
||||
m_VecFields = refOther.m_VecFields;
|
||||
m_VecIncluded = refOther.m_VecIncluded;
|
||||
m_bClustered = refOther.m_bClustered;
|
||||
m_bUnique = refOther.m_bUnique;
|
||||
m_nFillFactor = refOther.m_nFillFactor;
|
||||
Q_strncpy( m_szIndexName, refOther.m_szIndexName, Q_ARRAYSIZE( m_szIndexName ) );
|
||||
|
||||
}
|
||||
|
||||
// get count of fields in this index
|
||||
int GetCount() const
|
||||
{
|
||||
return m_VecFields.Count();
|
||||
}
|
||||
|
||||
// get count of included fields in this index
|
||||
int GetIncludedCount() const
|
||||
{
|
||||
return m_VecIncluded.Count();
|
||||
}
|
||||
|
||||
void AddIncludedColumn( int nIndex )
|
||||
{
|
||||
m_VecIncluded.AddToTail( nIndex );
|
||||
}
|
||||
|
||||
void AddIncludedColumns( const CUtlVector<int> &refVec )
|
||||
{
|
||||
m_VecIncluded.AddVectorToTail( refVec );
|
||||
}
|
||||
|
||||
// get a particular field ID
|
||||
// the returned index is into the VecFields of the associated schema
|
||||
int GetField( int nIndex ) const
|
||||
{
|
||||
return m_VecFields[ nIndex ];
|
||||
}
|
||||
|
||||
int GetIncludedField( int nIndex ) const
|
||||
{
|
||||
return m_VecIncluded[ nIndex ];
|
||||
}
|
||||
|
||||
// is this index clustered?
|
||||
bool IsClustered() const
|
||||
{
|
||||
return m_bClustered;
|
||||
}
|
||||
|
||||
// is this index unique?
|
||||
bool IsUnique() const
|
||||
{
|
||||
return m_bUnique;
|
||||
}
|
||||
|
||||
void SetClustered( bool bIsClustered )
|
||||
{
|
||||
m_bClustered = bIsClustered;
|
||||
}
|
||||
|
||||
void SetFillFactor( int nFactor )
|
||||
{
|
||||
Assert( nFactor >= 0 && nFactor <= 100 );
|
||||
m_nFillFactor = nFactor;
|
||||
}
|
||||
|
||||
int GetFillFactor( ) const
|
||||
{
|
||||
return m_nFillFactor;
|
||||
}
|
||||
|
||||
const char* GetIndexName() const
|
||||
{
|
||||
return m_szIndexName;
|
||||
}
|
||||
|
||||
// determine if this fieldset is equal to the other one
|
||||
static bool CompareFieldSets( const FieldSet_t& refThis, CRecordInfo* pRecordInfoThis,
|
||||
const FieldSet_t& refOther, CRecordInfo* pRecordInfoOther );
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
// Validate our internal structures
|
||||
void Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
VALIDATE_SCOPE();
|
||||
m_VecFields.Validate( validator, "m_VecFields" );
|
||||
m_VecIncluded.Validate( validator, "m_VecIncluded" );
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
CUtlVector<int> m_VecFields; // ids of fields; indexes into m_VecFields of CSchema for a table
|
||||
CUtlVector<int> m_VecIncluded; // ids of included fields
|
||||
int m_nFillFactor; // fill factor for the index; zero means to use the server's default
|
||||
char m_szIndexName[k_cSQLObjectNameMax]; // name of this index
|
||||
bool m_bClustered:1; // is this index clustered?
|
||||
bool m_bUnique:1; // is this index unique?
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum ESchemaCatalog
|
||||
{
|
||||
k_ESchemaCatalogInvalid = -1,
|
||||
k_ESchemaCatalogMain = 0, // main GC catalog
|
||||
k_ESchemaCatalogOGS = 4, // operational game stats
|
||||
};
|
||||
|
||||
extern const char* PchNameFromESchemaCatalog( ESchemaCatalog e );
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CSchema
|
||||
// This defines the schema for a single table. The schema essentially defines
|
||||
// what's in the table (ie, field 0 is a 32 char string called "Name", etc.)
|
||||
// The schema is in charge of manipulating individual records within the table.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
class CSchemaFull;
|
||||
|
||||
class CSchema
|
||||
{
|
||||
public:
|
||||
|
||||
// Constructors & destructors
|
||||
CSchema();
|
||||
~CSchema();
|
||||
|
||||
// Recalculates field offsets and maximum record size.
|
||||
// Must be called after changing schema.
|
||||
void CalcOffsets();
|
||||
|
||||
// called to make final calculations when all fields/indexes/etc have been added and the schema is ready to be used
|
||||
void PrepareForUse();
|
||||
|
||||
// Sizing information
|
||||
uint32 CubSerialSchema() const { return( sizeof( SerSchema_t ) + m_VecField.Count() * sizeof( SerField_t ) ); }
|
||||
|
||||
// Size of total fixed-length portion of record
|
||||
uint32 CubRecordFixed() const { return( m_cubRecord ); }
|
||||
|
||||
// Size of the total variable-length portion of record (zero if no var-length fields)
|
||||
uint32 CubRecordVariable( const void *pvRecord ) const;
|
||||
|
||||
// Does this record have variable-length fields?
|
||||
bool BHasVariableFields() const { return m_bHasVarFields; }
|
||||
|
||||
VarFieldBlockInfo_t* PVarFieldBlockInfoFromRecord( const void *pvRecord ) const;
|
||||
|
||||
// Access field data - fixed or variable (may return NULL/0 for empty var field)
|
||||
bool BGetFieldData( const void *pvRecord, int iField, uint8 **ppubField, uint32 *pcubField ) const;
|
||||
bool BSetFieldData( void *pvRecord, int iField, uint8 *pubField, uint32 cubField, bool *pbVarBlockRealloced );
|
||||
|
||||
bool BGetVarField( const void *pvRecord, const VarField_t *pVarField, uint8 **ppubField, uint32 *pcubField ) const;
|
||||
bool BSetVarField( void *pvRecord, VarField_t *pVarField, const void *pvData, uint32 cubData, bool *pbRealloced, bool bFreeOnRealloc );
|
||||
|
||||
// Adjust var-block pointer, if present, to point just after the fixed part of the record
|
||||
void FixupDeserializedRecord( void *pvRecord );
|
||||
|
||||
// Render a record in text format
|
||||
void RenderRecord( uint8 *pubRecord );
|
||||
void RenderField( uint8 *pubRecord, int iField, int cchBuffer, char *pchBuffer );
|
||||
|
||||
// Accessors
|
||||
void SetITable( int iTable ) { m_iTable = iTable; }
|
||||
int GetITable() const { return m_iTable; }
|
||||
int GetCField() const { return m_VecField.Count(); }
|
||||
void SetReportingInterval( int nInterval ) { m_nReportingInterval = nInterval; }
|
||||
int GetReportingInterval( ) const { return m_nReportingInterval; }
|
||||
Field_t &GetField( int iField ) { return m_VecField[iField]; }
|
||||
const Field_t &GetField( int iField ) const { return m_VecField[iField]; }
|
||||
VarField_t *GetPVarField( void *pvRecord, int iField ) { return ( VarField_t * )( ( uint8 * ) pvRecord + m_VecField[iField].m_dubOffset ); }
|
||||
void SetName( const char *pchName ) { Q_strncpy( m_rgchName, pchName, sizeof( m_rgchName ) ); }
|
||||
const char *GetPchName() const { return m_rgchName; }
|
||||
const FieldSet_t& GetPKFields() { Assert( m_iPKIndex != -1 ); return GetIndexes()[m_iPKIndex]; }
|
||||
int GetPKIndex() const { return m_iPKIndex; }
|
||||
const CUtlVector<FieldSet_t>& GetIndexes() { return m_VecIndexes; }
|
||||
const CUtlVector<int>& GetFTSColumns() { return m_VecFullTextIndexes; }
|
||||
int GetFTSIndexCatalog() const { return m_nFullTextIndexCatalog; }
|
||||
|
||||
ESchemaCatalog GetESchemaCatalog() const { return m_eSchemaCatalog; }
|
||||
void SetESchemaCatalog( ESchemaCatalog eSchemaCatalog ) { m_eSchemaCatalog = eSchemaCatalog; }
|
||||
|
||||
// If cRecordMax is non-zero, this is a rolling table that only
|
||||
// holds on to cRecordMax records at most.
|
||||
void SetCRecordMax( int cRecordMax ) { m_cRecordMax = cRecordMax; }
|
||||
int GetCRecordMax() const { return m_cRecordMax; }
|
||||
|
||||
// Is this table for TESTs only?
|
||||
void SetBTestTable( bool bTestTable ) { m_bTestTable = bTestTable; }
|
||||
bool GetBTestTable() const { return m_bTestTable; }
|
||||
|
||||
// Randomly init a record or field to random values
|
||||
void InitRecordRandom( uint8 *pubRecord, uint32 unPrimaryIndex, bool *pbVarBlockRealloced, bool bFreeVarBlockOnRealloc );
|
||||
void SetFieldRandom( uint8 *pubRecord, int iField, bool *pbVarBlockRealloced, bool bFreeVarBlockOnRealloc );
|
||||
|
||||
// Checksum the schema
|
||||
uint32 CalcChecksum();
|
||||
|
||||
// pre-allocate space in the field array
|
||||
void EnsureFieldCount( int cFields )
|
||||
{
|
||||
m_VecField.EnsureCapacity( cFields );
|
||||
}
|
||||
|
||||
// This adds a field from our intrinsic schema to us
|
||||
void AddField( char *pchName, char *pchSQLName, EGCSQLType eType, uint32 cubSize, int cchMaxLength );
|
||||
void AddIntField( char *pchName, char *pchSQLName, EGCSQLType eType, int cubSize );
|
||||
|
||||
// We want to make a particular field the primary key
|
||||
int PrimaryKey( bool bClustered, int nFillFactor, const char *pchName );
|
||||
|
||||
// we want to make a particular list of fields the primary key
|
||||
int PrimaryKeys( bool bClustered, int nFillFactor, const char *pchNames );
|
||||
|
||||
// We want to index a particular field by name
|
||||
int IndexField( const char *pchName, const char *pchIndexName );
|
||||
|
||||
// We want to index a particular list of fields in a group
|
||||
int IndexFields( const char *pchIndexName, const char *pchNames );
|
||||
|
||||
// We want a certain index to additionally include a list of fields
|
||||
void AddIncludedFields( const char *pchIndexName, const char *pchNames );
|
||||
|
||||
// We want to unique index a particular list of fields in a group
|
||||
int UniqueFields( const char *pchIndexName, const char *pchNames );
|
||||
|
||||
// add a full-text index to the given column
|
||||
void AddFullTextIndex( CSchemaFull *pSchemaFull, const char *pchCatalogName, const char *pchColumnName );
|
||||
|
||||
// We want to index a particular field by field number
|
||||
// (field number is an index into the m_VecField array)
|
||||
int AddIndexToFieldNumber( int iField, const char *pchIndexName, bool bClustered );
|
||||
|
||||
// We want to index a particular set of fields
|
||||
// pchNames includes the names, separated by commas, of each field
|
||||
int AddIndexToFieldList( const char *pchNames, const char *pchIndexName, int nFlags, int nFillFactor );
|
||||
|
||||
// We want a unique index on a particular field
|
||||
int UniqueField( const char *pchName, const char *pchIndexName );
|
||||
|
||||
// We want to have a clustered index on a particular field by name
|
||||
int ClusteredIndexField( int nFillFactor, const char *pchName, const char *pchIndexName );
|
||||
|
||||
// We want to index a particular list of fields in a group
|
||||
int ClusteredIndexFields( int nFillFactor, const char *pchIndexName, const char *pchNames );
|
||||
|
||||
// We want an autoinc on a particular field
|
||||
void AutoIncrementField( char *pchName );
|
||||
|
||||
// catalog on which we'll enable FTS
|
||||
void EnableFTS( ESchemaCatalog eCatalog );
|
||||
|
||||
// adds a full text catalog with the given name on the identified fileset
|
||||
void AddFullTextCatalog( ESchemaCatalog eCatalog, const char *pstrCatalogName, const char *pstrFileGroupName );
|
||||
|
||||
// Adds a FK on the table
|
||||
void AddFK( const char* pchName, const char* pchColumn, const char* pchParentTable, const char* pchParentColumn, EForeignKeyAction eOnDeleteAction, EForeignKeyAction eOnUpdateAction );
|
||||
|
||||
// Access FK data
|
||||
int GetFKCount();
|
||||
FKData_t &GetFKData( int iIndex );
|
||||
|
||||
void SetTestWipePolicy( EWipePolicy policy ) { m_wipePolicy = policy; }
|
||||
EWipePolicy GetTestWipePolicy() const { return m_wipePolicy; }
|
||||
|
||||
void SetBAllowWipeTableInProd( bool bVal ) { m_bAllowWipeInProd = bVal; }
|
||||
bool BAllowWipeTableInProd() const { return m_bAllowWipeInProd; }
|
||||
|
||||
void SetPrepopulatedTable( ) { m_bPrepopulatedTable = true; }
|
||||
bool BPrepopulatedTable( ) const { return m_bPrepopulatedTable; }
|
||||
|
||||
// Find the field with a given name (returns k_iFieldNil if not found)
|
||||
int FindIField( const char *pchName );
|
||||
int FindIFieldSQL( const char *pchName );
|
||||
|
||||
// Helper functions for recording schema conversion operations
|
||||
void AddDeleteField( const char *pchFieldName );
|
||||
void AddRenameField( const char *pchFieldNameOld, const char *pchFieldNameNew );
|
||||
void AddAlterField( const char *pchFieldNameOld, const char *pchFieldNameNew, PfnAlterField_t pfnAlterField );
|
||||
|
||||
// Schema conversion helper: figure out what field to map a field from a different schema to
|
||||
bool BCanConvertField( const char *pchFieldSrc, int *piFieldDst, PfnAlterField_t *ppfnAlterField );
|
||||
|
||||
CRecordInfo *GetRecordInfo() { return m_pRecordInfo; }
|
||||
const CRecordInfo *GetRecordInfo() const { return m_pRecordInfo; }
|
||||
|
||||
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
|
||||
void ValidateRecord( uint8 *pubRecord ); // Validate a record that uses our schema
|
||||
|
||||
private:
|
||||
int m_iTable; // The index of our table
|
||||
int m_iPKIndex; // index into of m_VecIndexes of our PK index; k_iFieldNil if no PK
|
||||
char m_rgchName[k_cSQLObjectNameMax]; // Name of this table
|
||||
CUtlVector<Field_t> m_VecField; // All the fields that make up the schema
|
||||
CUtlVector<FieldSet_t> m_VecIndexes; // vector of all fields in all indexes
|
||||
int m_cRecordMax; // Max # records in the table (for rolling tables)
|
||||
bool m_bTestTable; // Table exists only for tests
|
||||
bool m_bAllowWipeInProd; // should we allow WipeTable operations on this table in the beta/public universe?
|
||||
EWipePolicy m_wipePolicy; // should this table be wiped between all tests, no tests, or non-stress tests?
|
||||
bool m_bHasVarFields; // True if this table has variable-length fields
|
||||
bool m_bPrepopulatedTable; // true if this table is pre-populated
|
||||
EPrimaryKeyType m_nHasPrimaryKey; // what kind of PK do we have, if any?
|
||||
CRecordInfo *m_pRecordInfo; // The record description corresponding to this schema. (Similar info, record description is new form, have both for a while during DS->SQL switch)
|
||||
CUtlVector<int> m_VecFullTextIndexes; // vector of indexes into m_VecField of fields covered by this table's full-text index.
|
||||
int m_nFullTextIndexCatalog; // index of catalog to use for creating full-text indexes
|
||||
CUtlVector<FKData_t> m_VecFKData; // data on foreign keys for this schema object
|
||||
|
||||
uint32 m_cubRecord; // Binary record length
|
||||
int m_nReportingInterval; // reporting interval of this table if stats; 0 if not stats
|
||||
ESchemaCatalog m_eSchemaCatalog; // what catalog does this table live in?
|
||||
|
||||
// Schema conversion instructions
|
||||
CUtlVector<DeleteField_t> m_VecDeleteField;
|
||||
CUtlVector<RenameField_t> m_VecRenameField;
|
||||
CUtlVector<AlterField_t> m_VecAlterField;
|
||||
};
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // GCSCHEMA_H
|
||||
283
public/gcsdk/sqlaccess/schemafull.h
Normal file
283
public/gcsdk/sqlaccess/schemafull.h
Normal file
@@ -0,0 +1,283 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GCSCHEMAFULL_H
|
||||
#define GCSCHEMAFULL_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SerSchemaFull
|
||||
// This defines the binary serialization format for a CSchemaFull
|
||||
//-----------------------------------------------------------------------------
|
||||
struct SerSchemaFull_t
|
||||
{
|
||||
enum EVersion
|
||||
{
|
||||
k_ECurrentVersion = 1,
|
||||
};
|
||||
|
||||
int32 m_nVersion; // version of serialization format
|
||||
int32 m_cSchema; // # of schema we contain
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CFTSCatalogInfo
|
||||
// information about a full text search catalog object in our schema
|
||||
//-----------------------------------------------------------------------------
|
||||
class CFTSCatalogInfo
|
||||
{
|
||||
public:
|
||||
enum ESchemaCatalog m_eCatalog;
|
||||
const char *m_pstrName;
|
||||
int m_nFileGroup;
|
||||
|
||||
CFTSCatalogInfo()
|
||||
: m_pstrName( NULL ),
|
||||
m_eCatalog( k_ESchemaCatalogInvalid )
|
||||
{
|
||||
}
|
||||
|
||||
~CFTSCatalogInfo()
|
||||
{
|
||||
free( (void*) m_pstrName);
|
||||
}
|
||||
|
||||
CFTSCatalogInfo( const CFTSCatalogInfo &refOther )
|
||||
{
|
||||
m_eCatalog = refOther.m_eCatalog;
|
||||
m_nFileGroup = refOther.m_nFileGroup;
|
||||
if ( refOther.m_pstrName != NULL )
|
||||
m_pstrName = strdup( refOther.m_pstrName );
|
||||
else
|
||||
m_pstrName = NULL;
|
||||
}
|
||||
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName ) // Validate our internal structures
|
||||
{
|
||||
validator.ClaimMemory( (void *) m_pstrName );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SchemaFull conversion instructions
|
||||
// These specify various operations that can be performed when converting
|
||||
// from one SchemaFull to another.
|
||||
//-----------------------------------------------------------------------------
|
||||
struct DeleteTable_t
|
||||
{
|
||||
char m_rgchTableName[k_cSQLObjectNameMax]; // Name of the table to delete
|
||||
};
|
||||
|
||||
struct RenameTable_t
|
||||
{
|
||||
char m_rgchTableNameOld[k_cSQLObjectNameMax]; // Rename a table with this name
|
||||
int m_iTableDst; // to this table
|
||||
};
|
||||
|
||||
|
||||
enum ETriggerType
|
||||
{
|
||||
k_ETriggerType_Invalid,
|
||||
k_ETriggerType_After_Insert,
|
||||
k_ETriggerType_InsteadOf_Insert,
|
||||
k_ETriggerType_After_Delete,
|
||||
k_ETriggerType_InsteadOf_Delete,
|
||||
k_ETriggerType_After_Update,
|
||||
k_ETriggerType_InsteadOf_Update,
|
||||
};
|
||||
|
||||
class CTriggerInfo
|
||||
{
|
||||
public:
|
||||
CTriggerInfo()
|
||||
: m_eTriggerType( k_ETriggerType_Invalid ),
|
||||
m_bMatched( false )
|
||||
{
|
||||
}
|
||||
|
||||
// are these equal for identity?
|
||||
bool operator==( const CTriggerInfo& refOther ) const
|
||||
{
|
||||
if ( 0 != Q_stricmp( m_szTriggerTableName, refOther.m_szTriggerTableName ) )
|
||||
return false;
|
||||
if ( 0 != Q_stricmp( m_szTriggerName, refOther.m_szTriggerName ) )
|
||||
return false;
|
||||
|
||||
// they're equal!
|
||||
return true;
|
||||
}
|
||||
|
||||
// if the identity is the same, this will tell if text or type differs
|
||||
bool IsDifferent( const CTriggerInfo& refOther ) const
|
||||
{
|
||||
if ( m_eTriggerType != refOther.m_eTriggerType )
|
||||
return false;
|
||||
if ( m_strText != refOther.m_strText )
|
||||
return false;
|
||||
|
||||
// they're equal!
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* GetTriggerTypeString() const
|
||||
{
|
||||
const char *pstrSQL = "~~ unknown trigger type syntax error ~~";
|
||||
|
||||
switch ( m_eTriggerType )
|
||||
{
|
||||
case k_ETriggerType_After_Insert:
|
||||
pstrSQL = "AFTER INSERT";
|
||||
break;
|
||||
case k_ETriggerType_InsteadOf_Insert:
|
||||
pstrSQL = "INSTEAD OF INSERT";
|
||||
break;
|
||||
case k_ETriggerType_After_Delete:
|
||||
pstrSQL = "AFTER DELETE";
|
||||
break;
|
||||
case k_ETriggerType_InsteadOf_Delete:
|
||||
pstrSQL = "INSTEAD OF DELETE";
|
||||
break;
|
||||
case k_ETriggerType_After_Update:
|
||||
pstrSQL = "AFTER UPDATE";
|
||||
break;
|
||||
case k_ETriggerType_InsteadOf_Update:
|
||||
pstrSQL = "INSTEAD OF UPDATE";
|
||||
break;
|
||||
|
||||
default:
|
||||
case k_ETriggerType_Invalid:
|
||||
/* initialize is fine, thanks */
|
||||
break;
|
||||
}
|
||||
|
||||
return pstrSQL;
|
||||
}
|
||||
|
||||
bool m_bMatched; // got matched during schema convert
|
||||
ETriggerType m_eTriggerType; // what kinda trigger is this?
|
||||
ESchemaCatalog m_eSchemaCatalog; // catalog where this trigger lives
|
||||
char m_szTriggerName[k_cSQLObjectNameMax]; // name of the trigger object
|
||||
char m_szTriggerTableName[k_cSQLObjectNameMax]; // name of the table hosting this trigger
|
||||
CUtlString m_strText; // text of the trigger
|
||||
|
||||
// Validate our internal structures
|
||||
#ifdef DBGFLAG_VALIDATE
|
||||
void Validate( CValidator &validator, const char *pchName )
|
||||
{
|
||||
m_strText.Validate( validator, pchName );
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// CSchemaFull
|
||||
// This defines the schema for the entire data store. It's essentially just
|
||||
// a collection of CSchema, which define the schema for individual tables.
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSchemaFull
|
||||
{
|
||||
public:
|
||||
// Constructors & destructors
|
||||
CSchemaFull();
|
||||
~CSchemaFull();
|
||||
|
||||
void Uninit();
|
||||
|
||||
// add a new schema and return its pointer.
|
||||
CSchema *AddNewSchema( int iTable, ESchemaCatalog eCatalog, const char *pstrName )
|
||||
{
|
||||
CSchema &refNewSchema = m_VecSchema[m_VecSchema.AddToTail()];
|
||||
refNewSchema.SetName( pstrName );
|
||||
refNewSchema.SetESchemaCatalog( eCatalog );
|
||||
SetITable( &refNewSchema, iTable );
|
||||
return &refNewSchema;
|
||||
}
|
||||
|
||||
|
||||
// Accessors
|
||||
int GetCSchema() const { return m_VecSchema.Count(); }
|
||||
CSchema &GetSchema( int iSchema ) { return m_VecSchema[iSchema]; }
|
||||
uint32 GetCheckSum() const { return m_unCheckSum; }
|
||||
|
||||
uint8 *GetPubScratchBuffer( );
|
||||
uint32 GetCubScratchBuffer() const { return m_cubScratchBuffer; }
|
||||
|
||||
// Makes sure that a generated intrinsic schema is consistent
|
||||
void CheckSchema( CSchema *pSchema, int cField, uint32 cubRecord );
|
||||
|
||||
// Find the table with a given name (returns -1 if not found)
|
||||
int FindITable( const char *pchName );
|
||||
const char *PchTableFromITable( int iTable );
|
||||
|
||||
// Helper functions for recording schema conversion operations
|
||||
void AddDeleteTable( const char *pchTableName );
|
||||
void AddRenameTable( const char *pchTableNameOld, const char *pchTableNameNew );
|
||||
void AddDeleteField( const char *pchTableName, const char *pchFieldName );
|
||||
void AddRenameField( const char *pchTableName, const char *pchFieldNameOld, const char *pchFieldNameNew );
|
||||
void AddAlterField( const char *pchTableName, const char *pchFieldNameOld, const char *pchFieldNameNew, PfnAlterField_t pfnAlterField );
|
||||
|
||||
// declare that a trigger is on a table
|
||||
void AddTrigger( ESchemaCatalog eCatalog, const char *pchTableName, const char *pchTriggerName, ETriggerType eTriggerType, const char *pchTriggerText );
|
||||
|
||||
// Schema conversion helper: figure out what table to map a table from a different schema to
|
||||
bool BCanConvertTable( const char *pchTableSrc, int *piTableDst );
|
||||
|
||||
// full text catalogs
|
||||
void AddFullTextCatalog( enum ESchemaCatalog eCatalog, const char *pstrCatalogName, int nFileGroup );
|
||||
int GetFTSCatalogByName( enum ESchemaCatalog eCatalog, const char *pstrCatalogName );
|
||||
void EnableFTS( enum ESchemaCatalog eCatalog );
|
||||
int GetCFTSCatalogs() const { return m_vecFTSCatalogs.Count(); }
|
||||
const CFTSCatalogInfo & GetFTSCatalogInfo( int nIndex ) const { return m_vecFTSCatalogs[nIndex]; }
|
||||
|
||||
const CUtlVector< CTriggerInfo> & GetTriggerInfos( ) const { return m_VecTriggers; }
|
||||
|
||||
// is the given schema catalog FTS enabled?
|
||||
bool GetFTSEnabled( enum ESchemaCatalog eCatalog );
|
||||
|
||||
void Validate( CValidator &validator, const char *pchName ); // Validate our internal structures
|
||||
|
||||
// sets tableID on CSchema, checking that it is not a duplicate
|
||||
void SetITable( CSchema* pSchema, int iTable );
|
||||
void FinishInit(); // Recalculates some internal fields
|
||||
private:
|
||||
|
||||
|
||||
CUtlVector< CSchema > m_VecSchema; // Schema for tables in all catalogs
|
||||
CUtlVector< CTriggerInfo > m_VecTriggers; // list of triggers in all catalogs
|
||||
|
||||
// which schema catalogs have FTS enabled?
|
||||
CUtlMap< ESchemaCatalog, bool > m_mapFTSEnabled;
|
||||
|
||||
// list of catalogs; each is marked with the schema where it lives.
|
||||
CUtlVector< CFTSCatalogInfo > m_vecFTSCatalogs;
|
||||
|
||||
uint32 m_unCheckSum; // A simple checksum of our contents
|
||||
|
||||
// SchemaFull conversion instructions
|
||||
CUtlVector<DeleteTable_t> m_VecDeleteTable;
|
||||
CUtlVector<RenameTable_t> m_VecRenameTable;
|
||||
|
||||
uint8 *m_pubScratchBuffer; // Big enough to hold any record or sparse record in this schemafull
|
||||
uint32 m_cubScratchBuffer; // Size of the scratch buffer
|
||||
};
|
||||
|
||||
extern CSchemaFull & GSchemaFull();
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // GCSCHEMAFULL_H
|
||||
91
public/gcsdk/sqlaccess/schemaupdate.h
Normal file
91
public/gcsdk/sqlaccess/schemaupdate.h
Normal file
@@ -0,0 +1,91 @@
|
||||
//====== Copyright <20>, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: Contains the job that's responsible for updating the database schema
|
||||
//
|
||||
//=============================================================================
|
||||
#ifndef UPDATESCHEMA_H
|
||||
#define UPDATESCHEMA_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
typedef CUtlMap<const char *,CRecordInfo *> CMapPRecordInfo;
|
||||
|
||||
enum EConversionMode
|
||||
{
|
||||
k_EConversionModeInspectOnly,
|
||||
k_EConversionModeConvertSafe,
|
||||
k_EConversionModeConvertIrreversible
|
||||
};
|
||||
|
||||
class CSchemaUpdate : public CRefCount
|
||||
{
|
||||
public:
|
||||
CSchemaUpdate();
|
||||
|
||||
void AddRecordInfoDesired( CRecordInfo *pRecordInfo );
|
||||
void AddFTSInfo( const CFTSCatalogInfo &refFTSInfo );
|
||||
void AddTriggerInfos( const CUtlVector< CTriggerInfo > &refTriggerInfo );
|
||||
|
||||
// input parameters
|
||||
CMapPRecordInfo m_mapPRecordInfoDesired;
|
||||
EConversionMode m_eConversionMode;
|
||||
CUtlLinkedList< CFTSCatalogInfo > m_listFTSCatalogInfo;
|
||||
CUtlVector< CTriggerInfo > m_vecTriggerInfo;
|
||||
|
||||
// output parameters
|
||||
bool m_bConversionNeeded;
|
||||
bool m_bSkippedAChange;
|
||||
int m_cTablesDesiredMissing;
|
||||
int m_cTablesActualDifferent;
|
||||
int m_cTablesActualUnknown;
|
||||
int m_cTablesNeedingChange;
|
||||
int m_cColumnsDesiredMissing;
|
||||
int m_cColumnsActualDifferent;
|
||||
int m_cColumnsActualUnknown;
|
||||
|
||||
CFmtStr1024 m_sDetail;
|
||||
|
||||
private:
|
||||
virtual ~CSchemaUpdate();
|
||||
};
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
class CJobUpdateSchema : public CGCJob
|
||||
{
|
||||
public:
|
||||
CJobUpdateSchema( CGCBase *pGC, int iTableCount ) : CGCJob( pGC ), m_mapSQLTypeToEType( DefLessFunc(int) ), m_iTableCount( iTableCount ) { }
|
||||
bool BYieldingRunJob( void * );
|
||||
private:
|
||||
bool BYieldingUpdateSchema( ESchemaCatalog eSchemaCatalog );
|
||||
SQLRETURN YieldingEnsureDatabaseSchemaCorrect( ESchemaCatalog eSchemaCatalog, CSchemaUpdate *pSchemaUpdate );
|
||||
EGCSQLType GetEGCSQLTypeForMSSQLType( int nType );
|
||||
bool YieldingBuildTypeMap( ESchemaCatalog eSchemaCatalog );
|
||||
SQLRETURN YieldingGetSchemaID( ESchemaCatalog eSchemaCatalog, int *pSchemaID );
|
||||
SQLRETURN YieldingGetRecordInfoForAllTables( ESchemaCatalog eSchemaCatalog, int nSchemaID, CMapPRecordInfo &mapPRecordInfo );
|
||||
SQLRETURN YieldingGetColumnInfoForTable( ESchemaCatalog eSchemaCatalog, CMapPRecordInfo &mapPRecordInfo, int nTableID, const char *pchTableName );
|
||||
SQLRETURN YieldingGetTableFKConstraints( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo );
|
||||
SQLRETURN YieldingGetColumnIndexes( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo );
|
||||
SQLRETURN YieldingGetTriggers( ESchemaCatalog eSchemaCatalog, int nSchemaID, CUtlVector< CTriggerInfo > &vecTriggerInfo );
|
||||
SQLRETURN YieldingCreateTable( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo );
|
||||
SQLRETURN YieldingAddIndex( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo );
|
||||
SQLRETURN YieldingAddIndex( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const FieldSet_t &refFields );
|
||||
SQLRETURN YieldingRemoveIndex( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo );
|
||||
SQLRETURN YieldingAlterTableAddColumn( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo );
|
||||
SQLRETURN YieldingAddConstraint( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo, int nColFlagConstraint );
|
||||
SQLRETURN YieldingRemoveConstraint( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo, int nColFlagConstraint );
|
||||
SQLRETURN YieldingChangeColumnTypeOrLength( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfoDesired );
|
||||
SQLRETURN YieldingChangeColumnProperties( ESchemaCatalog eSchemaCatalog, CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfoActual, const CColumnInfo *pColumnInfoDesired );
|
||||
SQLRETURN YieldingCreateTrigger( ESchemaCatalog eSchemaCatalog, CTriggerInfo &refTriggerInfo );
|
||||
SQLRETURN YieldingDropTrigger( ESchemaCatalog eSchemaCatalog, CTriggerInfo &refTriggerInfo );
|
||||
|
||||
CUtlMap<int,EGCSQLType> m_mapSQLTypeToEType;
|
||||
int m_iTableCount;
|
||||
};
|
||||
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // UPDATESCHEMA_H
|
||||
354
public/gcsdk/sqlaccess/sqlaccess.h
Normal file
354
public/gcsdk/sqlaccess/sqlaccess.h
Normal file
@@ -0,0 +1,354 @@
|
||||
//====== Copyright (c), Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: Provides access to SQL at a high level
|
||||
//
|
||||
//=============================================================================
|
||||
|
||||
#ifndef SQLACCESS_H
|
||||
#define SQLACCESS_H
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include "gcsdk/gcsqlquery.h"
|
||||
|
||||
#include "tier0/memdbgon.h"
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
class CGCSQLQuery;
|
||||
class CGCSQLQueryGroup;
|
||||
class CColumnSet;
|
||||
class CRecordType;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Provides access to SQL at a high level
|
||||
//-----------------------------------------------------------------------------
|
||||
class CSQLAccess
|
||||
{
|
||||
public:
|
||||
CSQLAccess( ESchemaCatalog eSchemaCatalog = k_ESchemaCatalogMain );
|
||||
~CSQLAccess( );
|
||||
|
||||
bool BBeginTransaction( const char *pchName );
|
||||
bool BCommitTransaction( bool bAllowEmpty = false );
|
||||
void RollbackTransaction();
|
||||
bool BInTransaction( ) const { return m_bInTransaction; }
|
||||
|
||||
bool BYieldingExecute( const char *pchName, const char *pchSQLCommand, uint32 *pcRowsAffected = NULL, bool bSpewOnError = true );
|
||||
bool BYieldingExecuteString( const char *pchName, const char *pchSQLCommand, CFmtStr1024 *psResult, uint32 *pcRowsAffected = NULL );
|
||||
bool BYieldingExecuteScalarInt( const char *pchName, const char *pchSQLCommand, int *pnResult, uint32 *pcRowsAffected = NULL );
|
||||
bool BYieldingExecuteScalarIntWithDefault( const char *pchName, const char *pchSQLCommand, int *pnResult, int iDefaultValue, uint32 *pcRowsAffected = NULL );
|
||||
bool BYieldingExecuteScalarUint32( const char *pchName, const char *pchSQLCommand, uint32 *punResult, uint32 *pcRowsAffected = NULL );
|
||||
bool BYieldingExecuteScalarUint32WithDefault( const char *pchName, const char *pchSQLCommand, uint32 *punResult, uint32 unDefaultValue, uint32 *pcRowsAffected = NULL );
|
||||
bool BYieldingWipeTable( int iTable );
|
||||
|
||||
template <typename TReturn, typename TCast>
|
||||
bool BYieldingExecuteSingleResult( const char *pchName, const char *pchSQLCommand, EGCSQLType eType, TReturn *pResult, uint32 *pcRowsAffected );
|
||||
template <typename TReturn, typename TCast>
|
||||
bool BYieldingExecuteSingleResultWithDefault( const char *pchName, const char *pchSQLCommand, EGCSQLType eType, TReturn *pResult, TReturn defaultValue, uint32 *pcRowsAffected );
|
||||
|
||||
// manipulating CRecordBase (i.e. CSch...) objects in the database
|
||||
bool BYieldingInsertRecord( CRecordBase *pRecordBase );
|
||||
bool BYieldingInsertWithIdentity( CRecordBase* pRecordBase ) ;
|
||||
bool BYieldingReadRecordWithWhereColumns( CRecordBase *pRecord, const CColumnSet & readSet, const CColumnSet & whereSet );
|
||||
|
||||
template< typename SchClass_t >
|
||||
bool BYieldingReadRecordFromPK( SchClass_t *pRecord );
|
||||
template< typename SchClass_t>
|
||||
bool BYieldingReadMultipleRecordsWithWhereColumns( CUtlVector< SchClass_t > *pvecRecords, const CColumnSet & whereSet, CUtlVector< SchClass_t > *pvecUnmatchedRecords = NULL );
|
||||
template< typename SchClass_t>
|
||||
bool BYieldingReadMultipleRecordsWithWhereColumns( CUtlVector< SchClass_t > *pvecRecords, const CColumnSet & readSet, const CColumnSet & whereSet, CUtlVector< SchClass_t > *pvecUnmatchedRecords = NULL );
|
||||
template< typename SchClass_t>
|
||||
bool BYieldingReadRecordsWithWhereClause( CUtlVector< SchClass_t > *pvecRecords, const char *pchWhereClause, const CColumnSet & readSet, const char *pchTopClause = NULL );
|
||||
template< typename SchClass_t>
|
||||
bool BYieldingReadRecordsWithQuery( CUtlVector< SchClass_t > *pvecRecords, const char *sQuery, const CColumnSet & readSet );
|
||||
bool BYieldingUpdateRecord( const CRecordBase &record, const CColumnSet & whereColumns, const CColumnSet & updateColumns );
|
||||
bool BYieldingDeleteRecord( const CRecordBase & record, const CColumnSet & whereColumns );
|
||||
|
||||
void AddRecordParameters( const CRecordBase &record, const CColumnSet & columnSet );
|
||||
|
||||
void AddBindParam( const char *pchValue );
|
||||
void AddBindParam( const int16 nValue );
|
||||
void AddBindParam( const uint16 uValue );
|
||||
void AddBindParam( const int32 nValue );
|
||||
void AddBindParam( const uint32 uValue );
|
||||
void AddBindParam( const uint64 ulValue );
|
||||
void AddBindParam( const uint8 *ubValue, const int cubValue );
|
||||
void AddBindParam( const float fValue );
|
||||
void AddBindParam( const double dValue );
|
||||
void ClearParams();
|
||||
IGCSQLResultSetList *GetResults();
|
||||
|
||||
uint32 GetResultSetCount();
|
||||
uint32 GetResultSetRowCount( uint32 unResultSet );
|
||||
CSQLRecord GetResultRecord( uint32 unResultSet, uint32 unRow );
|
||||
|
||||
private:
|
||||
enum EReadSingleResultResult
|
||||
{
|
||||
eReadSingle_Error, // something went wrong in the DB or the data was in a format we didn't expect
|
||||
eReadSingle_ResultFound, // we found a single result and copied the value -- all is well!
|
||||
eReadSingle_UseDefault, // we didn't find any results but we specified a value in advance for this case
|
||||
};
|
||||
|
||||
EReadSingleResultResult BYieldingExecuteSingleResultDataInternal( const char *pchName, const char *pchSQLCommand, EGCSQLType eType, uint8 **pubData, uint32 *punSize, uint32 *pcRowsAffected, bool bHasDefaultValue );
|
||||
|
||||
private:
|
||||
|
||||
CGCSQLQuery *CurrentQuery();
|
||||
ESchemaCatalog m_eSchemaCatalog;
|
||||
CGCSQLQuery *m_pCurrentQuery;
|
||||
CGCSQLQueryGroup *m_pQueryGroup;
|
||||
bool m_bInTransaction;
|
||||
};
|
||||
|
||||
#define FOR_EACH_SQL_RESULT( sqlAccess, resultSet, record ) \
|
||||
for( CSQLRecord record = (sqlAccess).GetResultRecord( resultSet, 0 ); record.IsValid(); record.NextRow() )
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: templatized version of querying for a single value
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename TReturn, typename TCast>
|
||||
bool CSQLAccess::BYieldingExecuteSingleResult( const char *pchName, const char *pchSQLCommand, EGCSQLType eType, TReturn *pResult, uint32 *pcRowsAffected )
|
||||
{
|
||||
uint8 *pubData;
|
||||
uint32 cubData;
|
||||
if( CSQLAccess::BYieldingExecuteSingleResultDataInternal( pchName, pchSQLCommand, eType, &pubData, &cubData, pcRowsAffected, false ) != eReadSingle_ResultFound )
|
||||
return false;
|
||||
|
||||
*pResult = *( (TCast *)pubData );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: templatized version of querying for a single value
|
||||
//-----------------------------------------------------------------------------
|
||||
template <typename TReturn, typename TCast>
|
||||
bool CSQLAccess::BYieldingExecuteSingleResultWithDefault( const char *pchName, const char *pchSQLCommand, EGCSQLType eType, TReturn *pResult, TReturn defaultValue, uint32 *pcRowsAffected )
|
||||
{
|
||||
uint8 *pubData;
|
||||
uint32 cubData;
|
||||
EReadSingleResultResult eResult = CSQLAccess::BYieldingExecuteSingleResultDataInternal( pchName, pchSQLCommand, eType, &pubData, &cubData, pcRowsAffected, true );
|
||||
|
||||
if ( eResult == eReadSingle_Error )
|
||||
return false;
|
||||
|
||||
if ( eResult == eReadSingle_ResultFound )
|
||||
{
|
||||
*pResult = *( (TCast *)pubData );
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert( eResult == eReadSingle_UseDefault );
|
||||
*pResult = defaultValue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reads the record with a given PK.
|
||||
// Input: pRecordBase - record to read
|
||||
// Output: true if successful, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
template < typename SchClass_t >
|
||||
bool CSQLAccess::BYieldingReadRecordFromPK( SchClass_t *pRecord )
|
||||
{
|
||||
CColumnSet csetWhere = CColumnSet::PrimaryKey< SchClass_t >();
|
||||
CColumnSet csetRead = CColumnSet::Inverse( csetWhere );
|
||||
return BYieldingReadRecordWithWhereColumns( pRecord, csetRead, csetWhere );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reads multiple records from the database based on the where columns
|
||||
// filled in for each record. If the record is not found in the database
|
||||
// it will be removed from pvecRecords. If pvecUnmatchedRecords is
|
||||
// provided, it will be populated with the unmatched records removed
|
||||
// from pvecRecords
|
||||
// Input: pvecRecords - The records to fill in from the database
|
||||
// whereSet - The set of columns to query on
|
||||
// (optional) pvecUnmatchedRecords - A vector to hold records which
|
||||
// are not found in the database
|
||||
// Output: true if successful, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename SchClass_t>
|
||||
bool CSQLAccess::BYieldingReadMultipleRecordsWithWhereColumns( CUtlVector< SchClass_t > *pvecRecords,
|
||||
const CColumnSet & whereSet,
|
||||
CUtlVector< SchClass_t > *pvecUnmatchedRecords /* = NULL */ )
|
||||
{
|
||||
CColumnSet readSet( GSchemaFull().GetSchema( SchClass_t::k_iTable ).GetRecordInfo() );
|
||||
readSet.MakeInverse( whereSet );
|
||||
return BYieldingReadMultipleRecordsWithWhereColumns( pvecRecords, readSet, whereSet, pvecUnmatchedRecords );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reads multiple records from the database based on the where columns
|
||||
// filled in for each record. If the record is not found in the database
|
||||
// it will be removed from pvecRecords. If pvecUnmatchedRecords is
|
||||
// provided, it will be populated with the unmatched records removed
|
||||
// from pvecRecords
|
||||
// Input: pvecRecords - The records to fill in from the database
|
||||
// readSet - The set of columns to fill in
|
||||
// whereSet - The set of columns to query on
|
||||
// (optional) pvecUnmatchedRecords - A vector to hold records which
|
||||
// are not found in the database
|
||||
// Output: true if successful, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename SchClass_t>
|
||||
bool CSQLAccess::BYieldingReadMultipleRecordsWithWhereColumns( CUtlVector< SchClass_t > *pvecRecords,
|
||||
const CColumnSet & readSet,
|
||||
const CColumnSet & whereSet,
|
||||
CUtlVector< SchClass_t > *pvecUnmatchedRecords /* = NULL */ )
|
||||
{
|
||||
AssertMsg( !BInTransaction(), "BYieldingReadMultipleRecordsWithWhereColumns is not supported in a transaction" );
|
||||
if( BInTransaction() )
|
||||
return false;
|
||||
|
||||
Assert( !readSet.IsEmpty() );
|
||||
if ( readSet.IsEmpty() )
|
||||
return false;
|
||||
|
||||
if ( pvecUnmatchedRecords )
|
||||
{
|
||||
pvecUnmatchedRecords->RemoveAll();
|
||||
}
|
||||
|
||||
// Build the query we'll use for each record
|
||||
CFmtStr1024 sStatement, sWhere;
|
||||
BuildSelectStatementText( &sStatement, readSet );
|
||||
BuildWhereClauseText( &sWhere, whereSet );
|
||||
sStatement.Append( " WHERE " );
|
||||
sStatement.Append( sWhere );
|
||||
|
||||
BBeginTransaction( CFmtStr1024( "BYieldingReadMultipleRecordsWithWhereColumns() - %s", sStatement.Access() ) );
|
||||
|
||||
// Batch this query for each record
|
||||
FOR_EACH_VEC( *pvecRecords, i )
|
||||
{
|
||||
AddRecordParameters( pvecRecords->Element( i ), whereSet );
|
||||
if( !BYieldingExecute( NULL, sStatement ) )
|
||||
return false;
|
||||
}
|
||||
|
||||
// Actually run the query
|
||||
if ( !BCommitTransaction() )
|
||||
return false;
|
||||
|
||||
Assert( GetResultSetCount() == (uint32)pvecRecords->Count() );
|
||||
if ( GetResultSetCount() != (uint32)pvecRecords->Count() )
|
||||
return false;
|
||||
|
||||
// Get the results. Reading backwards because if a record doesn't find a match we'll
|
||||
// remove it from the list
|
||||
FOR_EACH_VEC_BACK( *pvecRecords, i )
|
||||
{
|
||||
// make sure the types are the same
|
||||
IGCSQLResultSet *pResultSet = m_pQueryGroup->GetResults()->GetResultSet( i );
|
||||
Assert( pResultSet->GetRowCount() <= 1 );
|
||||
if ( pResultSet->GetRowCount() > 1 )
|
||||
return false;
|
||||
|
||||
if( pResultSet->GetRowCount() == 1 )
|
||||
{
|
||||
// We have a record in this set, read it in
|
||||
FOR_EACH_COLUMN_IN_SET( readSet, nColumnIndex )
|
||||
{
|
||||
EGCSQLType eRecordType = readSet.GetColumnInfo( nColumnIndex ).GetType();
|
||||
EGCSQLType eResultType = pResultSet->GetColumnType( nColumnIndex );
|
||||
|
||||
Assert( eResultType == eRecordType );
|
||||
if( eRecordType != eResultType )
|
||||
return false;
|
||||
}
|
||||
|
||||
CSQLRecord sqlRecord = GetResultRecord( i, 0 );
|
||||
|
||||
FOR_EACH_COLUMN_IN_SET( readSet, nColumnIndex )
|
||||
{
|
||||
uint8 *pubData;
|
||||
uint32 cubData;
|
||||
|
||||
DbgVerify( sqlRecord.BGetColumnData( nColumnIndex, &pubData, (int*)&cubData ) );
|
||||
DbgVerify( pvecRecords->Element( i ).BSetField( readSet.GetColumn( nColumnIndex ), pubData, cubData ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// This record did not match, remove it and add it to pvecUnmatchedRecords if needed
|
||||
if ( pvecUnmatchedRecords )
|
||||
{
|
||||
pvecUnmatchedRecords->AddToTail( pvecRecords->Element( i ) );
|
||||
}
|
||||
|
||||
pvecRecords->Remove( i );
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Reads a list of records from the DB according to the specified where
|
||||
// clause
|
||||
// Input: pRecordBase - record to insert
|
||||
// Output: true if successful, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename SchClass_t>
|
||||
bool CSQLAccess::BYieldingReadRecordsWithWhereClause( CUtlVector< SchClass_t > *pvecRecords, const char *pchWhereClause, const CColumnSet & readSet, const char *pchTopClause )
|
||||
{
|
||||
AssertMsg( !BInTransaction(), "BYieldingReadRecordsWithWhereClause is not supported in a transaction" );
|
||||
if( BInTransaction() )
|
||||
return false;
|
||||
|
||||
Assert( !readSet.IsEmpty() );
|
||||
CFmtStr1024 sStatement;
|
||||
BuildSelectStatementText( &sStatement, readSet, pchTopClause );
|
||||
Assert( pchWhereClause && *pchWhereClause );
|
||||
if( !pchWhereClause || !(*pchWhereClause) )
|
||||
return false;
|
||||
|
||||
CUtlString sFullStatement = sStatement.Access();
|
||||
sFullStatement += " WHERE ";
|
||||
sFullStatement += pchWhereClause;
|
||||
|
||||
return BYieldingReadRecordsWithQuery< SchClass_t >( pvecRecords, sFullStatement, readSet );
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Inserts a new record into the DB and reads non-insertable fields back
|
||||
// into the record.
|
||||
// Input: pRecordBase - record to insert
|
||||
// Output: true if successful, false otherwise
|
||||
//-----------------------------------------------------------------------------
|
||||
template< typename SchClass_t>
|
||||
bool CSQLAccess::BYieldingReadRecordsWithQuery( CUtlVector< SchClass_t > *pvecRecords, const char *sQuery, const CColumnSet & readSet )
|
||||
{
|
||||
AssertMsg( !BInTransaction(), "BYieldingReadRecordsWithQuery is not supported in a transaction" );
|
||||
if( BInTransaction() )
|
||||
return false;
|
||||
|
||||
Assert(!readSet.IsEmpty() );
|
||||
if( !BYieldingExecute( NULL, sQuery ) )
|
||||
return false;
|
||||
|
||||
Assert( GetResultSetCount() == 1 );
|
||||
if ( GetResultSetCount() != 1 )
|
||||
return false;
|
||||
|
||||
// make sure the types are the same
|
||||
IGCSQLResultSet *pResultSet = m_pQueryGroup->GetResults()->GetResultSet( 0 );
|
||||
return CopyResultToSchVector( pResultSet, readSet, pvecRecords );
|
||||
}
|
||||
|
||||
} // namespace GCSDK
|
||||
|
||||
#include "tier0/memdbgoff.h"
|
||||
|
||||
#endif // SQLACCESS_H
|
||||
54
public/gcsdk/sqlaccess/sqlrecord.h
Normal file
54
public/gcsdk/sqlaccess/sqlrecord.h
Normal file
@@ -0,0 +1,54 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef GCSQLRECORD_H
|
||||
#define GCSQLRECORD_H
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
|
||||
class CSQLRecord
|
||||
{
|
||||
public:
|
||||
CSQLRecord( uint32 unRow, IGCSQLResultSet *pResultSet );
|
||||
CSQLRecord( );
|
||||
~CSQLRecord();
|
||||
|
||||
void Init( uint32 unRow, IGCSQLResultSet *pResultSet );
|
||||
|
||||
bool BWriteToRecord( CRecordBase *pRecord, const CColumnSet & csWriteFields );
|
||||
bool BGetColumnData( uint32 unColumn, uint8 **ppubField, int *pcubField );
|
||||
bool BGetColumnData( uint32 unColumn, uint8 **ppubField, size_t *pcubField );
|
||||
bool BGetStringValue( uint32 unColumn, const char **ppchVal );
|
||||
bool BGetStringValue( uint32 unColumn, CFmtStr1024 *psVal );
|
||||
bool BGetIntValue( uint32 unColumn, int *pnVal );
|
||||
bool BGetInt16Value( uint32 unColumn, int16 *pnVal );
|
||||
bool BGetInt64Value( uint32 unColumn, int64 *puVal );
|
||||
bool BGetUint64Value( uint32 unColumn, uint64 *puVal );
|
||||
bool BGetByteValue( uint32 unColumn, byte *pVal );
|
||||
bool BGetBoolValue( uint32 unColumn, bool *pVal );
|
||||
bool BGetUint32Value( uint32 unColumn, uint32 *puVal );
|
||||
bool BGetUint16Value( uint32 unColumn, uint16 *puVal );
|
||||
bool BGetUint8Value( uint32 unColumn, uint8 *puVal );
|
||||
bool BGetFloatValue( uint32 unColumn, float *pfVal );
|
||||
bool BGetDoubleValue( uint32 unColumn, double *pdVal );
|
||||
|
||||
void RenderField( uint32 unColumn, int cchBuffer, char *pchBuffer );
|
||||
|
||||
bool NextRow();
|
||||
bool IsValid() const { return m_pResultSet != NULL; }
|
||||
|
||||
private:
|
||||
|
||||
|
||||
bool BValidateColumnIndex( uint32 unColumn );
|
||||
IGCSQLResultSet *m_pResultSet;
|
||||
uint32 m_unRow;
|
||||
};
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // GCSQLRECORD_H
|
||||
101
public/gcsdk/sqlaccess/sqlutil.h
Normal file
101
public/gcsdk/sqlaccess/sqlutil.h
Normal file
@@ -0,0 +1,101 @@
|
||||
//========= Copyright <20> 1996-2004, Valve LLC, All rights reserved. ============
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//=============================================================================
|
||||
|
||||
#ifndef SQLUTIL_H
|
||||
#define SQLUTIL_H
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
namespace GCSDK
|
||||
{
|
||||
// Returns a long (1024 char) string of "?,?,?,?,?"... for use in IN clauses or INSERT statements
|
||||
const char *GetInsertArgString();
|
||||
|
||||
void ConvertFieldToText( EGCSQLType eFieldType, uint8 *pubRecord, int cubRecord, char *rgchField, int cchField, bool bQuoteString = true );
|
||||
void ConvertFieldArrayToInText( const CColumnInfo &columnInfo, byte *pubData, int cubData, char *rgchResult, bool bForPreparedStatement );
|
||||
char *SQLTypeFromField( const CColumnInfo &colInfo, char *pchBuf, int cchBuf );
|
||||
void EscapeStringValue( char *rgchField, int cchField );
|
||||
void AppendConstraints( const CRecordInfo *pRecordInfo, const CColumnInfo *pColumnInfo, bool bForAdd, CFmtStrMax & sCmd );
|
||||
void AppendTableConstraints( CRecordInfo *pRecordInfo, CFmtStrMax & sCmd );
|
||||
void AppendConstraint( const char *pchTableName, const char *pchColumnName, int nColFlagConstraint, bool bForAdd, bool bClustered,
|
||||
CFmtStrMax & sCmd, int nFillFactor );
|
||||
//void BuildSelectStatementText( CUtlVector<CQuery> *pVecQuery, bool bForPreparedStatement, char *pchStatement, int cchStatement );
|
||||
void BuildInsertStatementText( CFmtStr1024 *psStatement, const CRecordInfo *pRecordInfo );
|
||||
void BuildInsertAndReadStatementText( CFmtStr1024 *psStatement, CUtlVector<int> *pvecOutputFields, const CRecordInfo *pRecordInfo ) ;
|
||||
void BuildSelectStatementText( CFmtStr1024 *psStatement, const CColumnSet & selectSet, const char *pchTopClause = NULL );
|
||||
void BuildUpdateStatementText( CFmtStr1024 *psStatement, const CColumnSet & columnSet );
|
||||
void BuildDeleteStatementText( CFmtStr1024 *psStatement, const CRecordInfo* pRecordInfo );
|
||||
void BuildWhereClauseText( CFmtStr1024 *psClause, const CColumnSet & columnSet );
|
||||
|
||||
template< typename T >
|
||||
bool CopyResultToSchVector( IGCSQLResultSet *pResultSet, const CColumnSet & readSet, CUtlVector< T > *pvecRecords )
|
||||
{
|
||||
if ( pResultSet->GetRowCount() == 0 )
|
||||
return true;
|
||||
|
||||
FOR_EACH_COLUMN_IN_SET( readSet, nColumnIndex )
|
||||
{
|
||||
EGCSQLType eRecordType = readSet.GetColumnInfo( nColumnIndex ).GetType();
|
||||
EGCSQLType eResultType = pResultSet->GetColumnType( nColumnIndex );
|
||||
|
||||
Assert( eResultType == eRecordType );
|
||||
if( eRecordType != eResultType )
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for( CSQLRecord sqlRecord( 0, pResultSet ); sqlRecord.IsValid(); sqlRecord.NextRow() )
|
||||
{
|
||||
int nRecord = pvecRecords->AddToTail();
|
||||
|
||||
FOR_EACH_COLUMN_IN_SET( readSet, nColumnIndex )
|
||||
{
|
||||
uint8 *pubData;
|
||||
uint32 cubData;
|
||||
|
||||
DbgVerify( sqlRecord.BGetColumnData( nColumnIndex, &pubData, (int*)&cubData ) );
|
||||
DbgVerify( pvecRecords->Element( nRecord ).BSetField( readSet.GetColumn( nColumnIndex), pubData, cubData ) );
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//EResult UpdateOrInsertUnique( CSQLAccess &sqlAccess, int iTable, int iField, CRecordBase *pRecordBase, int iIndexID );
|
||||
//bool BIsDuplicateInsertAttempt( const CSQLErrorInfo *pErr );
|
||||
|
||||
|
||||
#define EXIT_WITH_SQL_FAILURE( ret ) { nRet = ret; goto Exit; }
|
||||
|
||||
#define EXIT_ON_BOOL_FAILURE( bRet, msg ) \
|
||||
{ \
|
||||
if ( false == bRet ) \
|
||||
{ \
|
||||
SetSQLError( msg ); \
|
||||
nRet = SQL_ERROR; \
|
||||
goto Exit; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SAFE_CLOSE_STMT( x ) \
|
||||
if ( NULL != (x) ) \
|
||||
{ \
|
||||
SQLFreeHandle( SQL_HANDLE_STMT, (x) ); \
|
||||
(x) = NULL; \
|
||||
}
|
||||
|
||||
#define SAFE_FREE_HANDLE( x, y ) \
|
||||
if ( NULL != (x) ) \
|
||||
{ \
|
||||
SQLFreeHandle( y, (x) ); \
|
||||
(x) = NULL; \
|
||||
}
|
||||
|
||||
} // namespace GCSDK
|
||||
#endif // SQLUTIL_H
|
||||
Reference in New Issue
Block a user