LOAD.CPP

// load.cpp : Guide database loader sample program 
// 
// 
// This is a part of the Microsoft Foundation Classes C++ library. 
// Copyright (C) 1997 Microsoft Corporation 
// All rights reserved. 
// 
// This source code is only intended as a supplement to the 
// Broadcast Architecture Programmer's Reference. 
// See the reference for detailed information regarding 
// Broadcast Architecture. 
 
#include "stdafx.h" 
#include "Load.h" 
#include "tssutil.h" 
 
 
///////////////////////////////////////////////////////////////////////////// 
// CLoadApp 
 
BEGIN_MESSAGE_MAP(CLoadApp, CWinApp) 
//{{AFX_MSG_MAP(CLoadApp) 
// NOTE - the ClassWizard will add and remove mapping macros here. 
//    DO NOT EDIT what you see in these blocks of generated code! 
//}}AFX_MSG_MAP 
END_MESSAGE_MAP() 
 
///////////////////////////////////////////////////////////////////////////// 
// CLoadApp construction 
 
CLoadApp::CLoadApp() 
{ 
// TODO: add construction code here, 
// Place all significant initialization in InitInstance 
} 
 
///////////////////////////////////////////////////////////////////////////// 
// The one and only CLoadApp object 
 
CLoadApp theApp; 
 
 
// 
// This is the external entry point defined in the .DEF file that is used by 
// the generic loader app to call into the Sample loader. 
// 
extern "C" 
{ 
ExitCodeList APIENTRY 
EPG_DBLoad(int &argc, _TCHAR **argv, CdbDBEngine &db, PFNFORCEQUIT pfnForceQuit) 
{ 
 
    AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
 
    ExitCodeList rc = theApp.EPG_DBLoad(argc, argv, db, pfnForceQuit); 
  
if(theApp.m_lpfnDaoTerm) 
(*theApp.m_lpfnDaoTerm)(); 
 
return rc; 
} 
}; 
 
 
CLoadApp::CLoadCommandLineProc::CLoadCommandLineProc(void) 
{ 
    m_fPartial = FALSE; 
m_csRead = ""; 
} 
 
 
void 
CLoadApp::CLoadCommandLineProc::Partial(CString &csArg) 
// Process the cmd line switch that allows us to be 
// told to do a partial update 
{ 
    m_fPartial = TRUE; 
    return; 
} 
 
 
void 
CLoadApp::CLoadCommandLineProc::Read(CString &csArg) 
// Process the cmd line switch that gives a location to read loader data from 
{ 
    m_csRead = csArg; 
    return; 
} 
 
 
void 
CLoadApp::CLoadCommandLineProc::Help(CString &csArg) 
// Display the command line usage 
{ 
    AfxMessageBox(IDS_USAGE, MB_OK | MB_ICONSTOP); 
    return; 
} 
 
// This table tells the command line processor what to do for each valid argument. 
CLoadApp::CLoadCommandLineProc::CArgProcTable 
CLoadApp::CLoadCommandLineProc::acapArgs[] = 
{ 
    IDS_SWPARTIAL, (void (CCommandLineProc::*)(class CString &))CLoadApp::CLoadCommandLineProc::Partial, 
    IDS_SWREAD, (void (CCommandLineProc::*)(class CString &))CLoadApp::CLoadCommandLineProc::Read, 
    IDS_SWHELP, (void (CCommandLineProc::*)(class CString &))CLoadApp::CLoadCommandLineProc::Help, 
    -1, NULL, 
}; 
 
 
BOOLEAN 
CLoadApp::CLoadCommandLineProc::GetPositionalArgs(int &argc, _TCHAR **argv) 
{ 
    return TRUE; 
} 
 
 
// This is the main entry point into the loader class. 
ExitCodeList 
CLoadApp::EPG_DBLoad(int &argc, _TCHAR **argv, CdbDBEngine &db 
, PFNFORCEQUIT pfnForceQuit) 
{ 
ExitCodeListrc; 
 
    if(!m_clpCmds.ProcessCommandLine(IDS_SWITCHCHARS, argc, argv)) 
return EXIT_USAGE; 
 
theApp.m_pDAODB = &db; 
theApp.m_pfnForceQuit = pfnForceQuit; 
 
    try 
    { 
        if(EXIT_OK != (rc = InitMembers()))  
        return (rc); 
    
        rc = ProcessInput(m_clpCmds.m_fPartial, db); 
         
        return (rc); 
    } 
    catch (CException *e) 
    { 
        e->Delete(); 
 
        return (EXIT_FAIL_CEXCEPTION); 
    } 
    catch (CdbException cdbe) 
    { 
return (EXIT_FAIL_DBEXCEPTION); 
    }   
catch (ExitCodeList rc) 
    { 
return (rc); 
    } 
    catch (...) 
    { 
return (EXIT_FAIL); 
    } 
} 
 
// This reinitializes certain app class members 
ExitCodeList 
CLoadApp::InitMembers(void) 
{ 
DWORD rc; 
    
    // Incoming data is all gmt.  Set up app class time info 
    // for conversions 
    TIME_ZONE_INFORMATION tzi; 
    DWORD tzrc; 
    tzrc = ::GetTimeZoneInformation(&tzi); 
 
    CTimeSpan bias(0, 0, tzi.Bias, 0); 
    switch(tzrc) 
{ 
    case TIME_ZONE_ID_UNKNOWN: 
    break; 
case TIME_ZONE_ID_DAYLIGHT: 
{ 
CTimeSpan temp(0, 0, tzi.DaylightBias, 0); 
bias += temp; 
        break; 
} 
case TIME_ZONE_ID_STANDARD: 
{ 
            CTimeSpan temp(0, 0, tzi.StandardBias, 0); 
            bias += temp; 
break; 
} 
    default: 
THROWASSERT(0, EXIT_FAIL_GETTIMEZONE); 
        break; 
} 
    m_odtsTimeZoneAdjust.SetDateTimeSpan(bias.GetDays(), bias.GetHours(), bias.GetMinutes(), bias.GetSeconds()); 
m_codtGuideStartTime.SetStatus(COleDateTime::invalid); 
m_codtGuideEndTime.SetStatus(COleDateTime::invalid); 
 
    DWORD dwBytes = sizeof(m_lTuningSpace); 
    rc = TSS_GetTuningIDs(SZDTVLOADGUID, (DWORD *)&m_lTuningSpace, dwBytes); 
    if((!rc) /*|| (dwBytes != sizeof(m_lTuningSpace)) GFS - How cound this be true?*/) 
        return EXIT_FAIL_GETTUNINGSPACE; 
 
m_covTuningSpace = m_lTuningSpace; 
 
    //aux 
    rs = NULL; 
    r = NULL; 
    bp = NULL; 
    g = NULL; 
    sg = NULL; 
    sr = NULL; 
    // main 
    n = NULL; 
    s = NULL; 
    c = NULL; 
    cp = NULL; 
    csr = NULL; 
    e = NULL; 
    ep = NULL; 
    ts = NULL; 
    t = NULL; 
 
    return EXIT_OK; 
} 
 
 
ExitCodeList CLoadApp::ProcessInput(BOOLEAN fPartialUpdate, CdbDBEngine &db) 
{ 
    ExitCodeList rc = EXIT_OK; 
     
    COleDateTime m_odtStart(COleDateTime::GetCurrentTime()); 
    m_covNow = m_odtStart + m_odtsTimeZoneAdjust; 
     
CString csWSP; 
csWSP.LoadString(IDS_LOADERWORKSPACE); 
 
    try 
    { 
OpenTables(); 
 
db[csWSP].BeginTrans(); 
 
Handle(fPartialUpdate); 
 
        ClearOldEntries(db);  // delete anything from mpg time span that wasn't refreshed. 
 
ClearDanglingRefs(db);  // cleanup unused auxiliary records 
 
BlockCommit(db, EPGLDR_ACTIVE_COMMIT_STARTING, EPGLDR_ACTIVE_COMMIT_ENDING); 
 
CloseTables(); 
} 
    catch (CException *e) 
    { 
        e->Delete(); 
 
db[csWSP].Rollback(); 
 
        return (EXIT_FAIL_CEXCEPTION); // failed 
    } 
    catch (CdbException cdbe) 
    { 
db[csWSP].Rollback(); 
 
return (EXIT_FAIL_DBEXCEPTION); 
    }   
catch (ExitCodeList rc) 
    { 
db[csWSP].Rollback(); 
 
return (rc); 
    }   
catch (...) 
    { 
db[csWSP].Rollback(); 
 
return (EXIT_FAIL); 
    } 
 
#ifdef _DEBUG 
    if (afxTraceFlags & traceDatabase) 
    { 
        COleDateTime end_parse(COleDateTime::GetCurrentTime()); 
        COleDateTimeSpan duration(end_parse - m_odtStart); 
        afxDump << "end parse. length = " << ((ULONG)duration.GetTotalSeconds()) << "\r\n"; 
    } 
#endif 
 
    return rc; 
} 
 
// execute deletes on each table in proper order for 
// all records whose last tx hasn't been updated and 
// who's attached to stuff that overlaps in the mpg's time frame 
void CLoadApp::ClearOldEntries(CdbDBEngine &db) 
{ 
CString csWSP; 
csWSP.LoadString(IDS_LOADERWORKSPACE); 
 
    try 
    { 
CdbDatabase database = db[csWSP][(LONG) 0]; 
db[csWSP].BeginTrans(); 
 
COleDateTime codtStartTimeMinusDay = m_codtGuideStartTime; 
COleDateTimeSpan codtsDelta; 
codtsDelta.SetDateTimeSpan(1, 0, 0, 0); 
 
codtStartTimeMinusDay -= codtsDelta; 
 
// delete old timeslots with end time < mpg start time 
// this removes any showings that are finished 
        ExecuteActionQuery(database, IDS_DELETE_EXPIRED_TS, & (COleVariant) m_lTuningSpace, & (COleVariant) codtStartTimeMinusDay); 
 
        // delete unupdated timeslots with last update < now and start time < guide range end time 
        // this removes any showings that were in the mpg last time the loader ran 
        // but that aren't there now 
        ExecuteActionQuery(database, IDS_DELETE_OMITTED_TS, & (COleVariant) m_lTuningSpace, 
&m_covNow, & (COleVariant) m_codtGuideStartTime, & (COleVariant) m_codtGuideEndTime); 
 
        // the previous actions may have left episode or channels records which aren't referenced 
        // by any time slots. 
 
Commit(db); 
        
#ifdef _DEBUG 
        if (afxTraceFlags & traceDatabase) 
            TRACE0("clear old entries committed\r\n"); 
#endif 
    } 
    catch (CException *e) 
    { 
        e->Delete(); 
 
db[csWSP].Rollback(); 
 
#ifdef _DEBUG 
afxDump << "ClearOldEntries CException catch handler\r\n"; 
#endif 
        throw e; 
    } 
    catch (...) 
    { 
db[csWSP].Rollback(); 
         
#ifdef _DEBUG 
afxDump << "ClearOldEntries ... catch handler\r\n"; 
#endif 
        throw (EXIT_FAIL); 
    } 
} 
 
 
// execute deletes on each table in proper order for 
// all auxiliary record which aren't used by anyone 
// we now delete these dangling records and this completes the differencing portion 
// of the partial update 
void CLoadApp::ClearDanglingRefs(CdbDBEngine &db) 
{ 
CString csWSP; 
csWSP.LoadString(IDS_LOADERWORKSPACE); 
 
try 
{ 
CdbDatabase database = db[csWSP][(LONG) 0]; 
db[csWSP].BeginTrans(); 
 
        ExecuteActionQuery(database, IDS_DELETE_DANGLING_C); 
        ExecuteActionQuery(database, IDS_DELETE_DANGLING_E); 
        ExecuteActionQuery(database, IDS_DELETE_DANGLING_S); 
ExecuteActionQuery(database, IDS_DELETE_DANGLING_THEME); 
 
Commit(db); 
 
#ifdef _DEBUG 
        if (afxTraceFlags & traceDatabase) { 
            TRACE0("dangling deletes committed\r\n"); 
        } 
#endif 
    } 
    catch (CException *e) 
    { 
        e->Delete(); 
 
db[csWSP].Rollback(); 
 
#ifdef _DEBUG 
afxDump << "ClearDanglingRefs CException catch handler\r\n"; 
#endif 
        throw e; 
    } 
catch (...) 
{ 
db[csWSP].Rollback(); 
 
#ifdef _DEBUG 
afxDump << "ClearDanglingRefs ... catch handler\r\n"; 
#endif 
        throw (EXIT_FAIL); 
    } 
} 
 
// This method executes a query in the database 
void 
CLoadApp::ExecuteActionQuery(CdbDatabase &qd, int iStringID, COleVariant *p0 
, COleVariant *p1, COleVariant *p2, COleVariant *p3) 
{ 
    CString csDelQuery; 
 
  if ((*m_pfnForceQuit)()) 
throw (EXIT_ABORT); 
 
csDelQuery.LoadString(iStringID); 
 
CdbQueryDef qdbdd; 
 
qdbdd = qd.QueryDefs.Item((LPCTSTR) csDelQuery); 
    if (p0 != NULL) 
        qdbdd.Parameters[(LONG) 0].SetValue(*p0); 
    if (p1 != NULL) 
        qdbdd.Parameters[(LONG) 1].SetValue(*p1); 
    if (p2 != NULL) 
        qdbdd.Parameters[(LONG) 2].SetValue(*p2); 
    if (p3 != NULL) 
        qdbdd.Parameters[(LONG) 3].SetValue(*p3); 
 
    qdbdd.Execute(); 
 
    return; 
} 
 
 
void 
CLoadApp::Commit(CdbDBEngine &db, LONG lStartMessage, LONG lEndMessage) 
{ 
UINT uiMessage = RegisterWindowMessage(SZLOADERSTUBGUID); 
 
if(0 != lStartMessage) 
::PostMessage(HWND_BROADCAST, uiMessage, lStartMessage, 0); 
 
CString csWSP; 
csWSP.LoadString(IDS_LOADERWORKSPACE); 
db.Idle(); 
db[csWSP].CommitTrans(); 
 
if(0 != lEndMessage) 
::PostMessage(HWND_BROADCAST, uiMessage, lEndMessage, 0); 
} 
 
 
void 
CLoadApp::BlockCommit(CdbDBEngine &db, LONG lStartMessage, LONG lEndMessage) 
{ 
UINT uiMessage = RegisterWindowMessage(SZLOADERSTUBGUID); 
 
if(0 != lStartMessage) 
::SendMessageTimeout(HWND_BROADCAST, uiMessage, lStartMessage, 0, 
SMTO_NORMAL, 5 * 1000, NULL); 
CString csWSP; 
csWSP.LoadString(IDS_LOADERWORKSPACE); 
db.Idle(); 
db[csWSP].CommitTrans(); 
 
if(0 != lEndMessage) 
::PostMessage(HWND_BROADCAST, uiMessage, lEndMessage, 0); 
} 
 
 
// Open recordsets for each of the tables 
// Set each recordset to proper index 
void 
CLoadApp::OpenTables(VOID) 
{ 
     // aux 
    rs = new CRatingSystemRecordset(); 
    rs->OpenIndexed(IDS_RS_ADDKEY, dbOpenTable, NULL, 0); 
 
    r = new CRatingRecordset(); 
    r->OpenIndexed(IDS_R_ADDKEY, dbOpenTable, NULL, 0); 
 
    bp = new CBroadcastPropertyRecordset(); 
    bp->OpenIndexed(IDS_BP_ADDKEY, dbOpenTable, NULL, 0); 
     
    g = new CGenreRecordset(); 
    g->OpenIndexed(IDS_G_ADDKEY, dbOpenTable, NULL, 0); 
 
    sg = new CSubGenreRecordset(); 
    sg->OpenIndexed(IDS_SG_ADDKEY, dbOpenTable, NULL, 0); 
 
    sr = new CStreamTypeRecordset(); 
    sr->OpenIndexed(IDS_SR_ADDKEY, dbOpenTable, NULL, 0); 
 
    // main 
    n = new CNetworkRecordset(); 
    n->OpenIndexed(IDS_N_ADDKEY, dbOpenTable, NULL, 0); 
     
    s = new CStationRecordset(); 
    s->OpenIndexed(IDS_S_ADDKEY, dbOpenTable, NULL, 0); 
 
    c = new CChannelTRecordset(); 
    c->OpenIndexed(IDS_C_ADDKEY, dbOpenTable, NULL, 0); 
 
    cp = new CChannelPropertyRecordset(); 
    cp->OpenIndexed(IDS_CP_ADDKEY, dbOpenTable, NULL, 0); 
 
    csr = new CChannelStreamRecordset(); 
    csr->OpenIndexed(IDS_CSR_ADDKEY, dbOpenTable, NULL, 0); 
 
    e = new CEpisodeTRecordset(); 
    e->OpenIndexed(IDS_E_ADDKEY, dbOpenTable, NULL, 0); 
 
    ep = new CEpisodePropertyRecordset(); 
    ep->OpenIndexed(IDS_EP_ADDKEY, dbOpenTable, NULL, 0); 
 
    ts = new CTimeSlotRecordset(); 
    ts->OpenIndexed(IDS_TS_ADDKEY, dbOpenTable, NULL, 0); 
     
    t = new CThemeRecordset(); 
    t->OpenIndexed(IDS_T_ADDKEY, dbOpenTable, NULL, 0); 
} 
 
 
// close all of the tables 
void 
CLoadApp::CloseTables(void) 
{ 
    //aux 
    if (rs != NULL) { 
        rs->CloseRecordset(); 
        delete rs; 
        rs = NULL; 
    } 
    if (r != NULL) { 
        r->CloseRecordset(); 
        delete r; 
        r = NULL; 
    } 
    if (bp != NULL) { 
        bp->CloseRecordset(); 
        delete bp; 
        bp = NULL; 
    } 
    if (g != NULL) { 
        g->CloseRecordset(); 
        delete g; 
        g = NULL; 
    } 
    if (sg != NULL) { 
        sg->CloseRecordset(); 
        delete sg; 
        sg = NULL; 
    } 
    if (sr != NULL) { 
        sr->CloseRecordset(); 
        delete sr; 
        sr = NULL; 
    } 
    // main 
    if (n != NULL) { 
        n->CloseRecordset(); 
        delete n; 
        n = NULL; 
    } 
    if (s != NULL) { 
        s->CloseRecordset(); 
        delete s; 
        s = NULL; 
    } 
    if (c != NULL) { 
        c->CloseRecordset(); 
        delete c; 
        c = NULL; 
    } 
    if (cp != NULL) { 
        cp->CloseRecordset(); 
        delete cp; 
        cp = NULL; 
    } 
    if (csr != NULL) { 
        csr->CloseRecordset(); 
        delete csr; 
        csr = NULL; 
    } 
    if (e != NULL) { 
        e->CloseRecordset(); 
        delete e; 
        e = NULL; 
    } 
    if (ep != NULL) { 
        ep->CloseRecordset(); 
        delete ep; 
        ep = NULL; 
    } 
    if (ts != NULL) { 
        ts->CloseRecordset(); 
        delete ts; 
        ts = NULL; 
    } 
    if (t != NULL) { 
        t->CloseRecordset(); 
        delete t; 
        t = NULL; 
    } 
} 
 
 
// Put data into the Guide Database 
VOID 
CLoadApp::Handle(BOOL fPartialUpdate) 
{ 
// Add a station 
CStationcs(AFX_RFX_LONG_PSEUDO_NULL, "WGFS", "Sample Station" 
, 0// Network ID 
, "mylogo"// Logo 
, "The Sample station");// Description 
s->UpdateRS(cs); 
 
// Add a channel 
COleDateTime codtDummy = COleDateTime(1999, 12, 30, 0, 0, 0); 
CChannelTcct(AFX_RFX_LONG_PSEUDO_NULL 
, -2// Tuning space  
, 241// Channel number 
, codtDummy// Start time 
, codtDummy// End time 
, 0// Length 
, cs.StationID()// Station ID 
, "The Sample Channel"// Description 
, 0// Enhancement ID 
, 0// Rating ID 
, 0// Display mask 
, 0// Payment address 
, 0// Payment token 
, COleDateTime::GetCurrentTime() + m_odtsTimeZoneAdjust); // Last update 
 
c->UpdateRS(cct); 
 
// Add an episode 
CEpisodeT cet(AFX_RFX_LONG_PSEUDO_NULL 
, "The Sample Show"// Title 
, "Bringing you samples from around the world"// Description 
, 0// Enhancement ID 
, 0// Display mask 
, 0// Theme ID 
, 0// Rating ID 
, 255// Abbreviation 
, COleDateTime::GetCurrentTime() + m_odtsTimeZoneAdjust);// last update 
e->UpdateRS(cet); 
 
// Put the show in a time slot 
// Start the show at the top of the next hour 
COleDateTime codtStart = COleDateTime::GetCurrentTime(); 
codtStart.SetDateTime(codtStart.GetYear(), codtStart.GetMonth(), codtStart.GetDay() 
, codtStart.GetHour()+1, 0, 0); 
// Make it a half hour show 
COleDateTime codtEnd = codtStart + COleDateTimeSpan(0, 0, 30, 0); 
 
ts->UpdateRS(CTimeSlot(AFX_RFX_LONG_PSEUDO_NULL 
, cct.ChannelID()// Channel ID 
, cet.EpisodeID()// Eppisode ID 
, codtStart// Start time 
, codtEnd// End time 
, 30// Length 
, 0// Payment address 
, 0// Payment token 
, COleDateTime::GetCurrentTime() + m_odtsTimeZoneAdjust// Last update 
, FALSE// Pay-per-view 
, FALSE// Closed caption 
, FALSE// Stereo 
, FALSE// Re-run 
, FALSE// Tape inhibited 
, FALSE// Other properties 
, FALSE// Alternate data 
, FALSE));// Alternate audio 
 
}