Exemplo n.º 1
0
BOOL COledbDatabase::BeginTrans()
{
   return BeginTrans(ISOLATIONLEVEL_READCOMMITTED);
}
Exemplo n.º 2
0
/*----------------------------------------------------------------------------------------------
	Do the main loop of looking through all fields in the database that may include
	monolingual or multilingual strings.
----------------------------------------------------------------------------------------------*/
void DbStringCrawler::DoAll(int stid1, int stid2, bool fTrans, const OLECHAR * pszIdsTable)
{
	if (fTrans)
	{
		m_qodc.Clear();		// Can't have a command open when we start a transaction.
		BeginTrans();
		CreateCommand();
	}

	StrUni stuCmd;
	ComBool fMoreRows;
	ComBool fIsNull;
	unsigned long cbSpaceTaken;

	// Get the version number
	int nVer;
	stuCmd = L"select DbVer from version$";
	CheckHr(m_qodc->ExecCommand(stuCmd.Bstr(), knSqlStmtSelectWithOneRowset));
	CheckHr(m_qodc->GetRowset(0));
	CheckHr(m_qodc->NextRow(&fMoreRows));
	CheckHr(m_qodc->GetColValue(1, reinterpret_cast <BYTE *>(&nVer), sizeof(int),
		&cbSpaceTaken, &fIsNull, 0));

	int hobj = 0;
	int flid = 0;
	int encStr;
	Vector<byte> vbFmt;
	int cbFmt;

	int ieFix;
	Vector<int> vflidFix;
	Vector<int> vhobjFix;
	Vector<int> vwsFix;
	Vector<Vector<byte> > vvbFmtFix;

	ComVector<ITsTextProps> vqttp;
	Vector<int> vich;
	int cpttp;

	ITsPropsFactoryPtr qtpf;
	qtpf.CreateInstance(CLSID_TsPropsFactory);

	StrUni stuMsg;
	if (m_qadvi3)
	{
		stuMsg.Load(stid1);
		m_qadvi3->put_Message(stuMsg.Bstr());
	}

	// Review (SharonC): Does getting the count of the query results slow things down too much?

	// 1. Scan all multilingual formatted strings for embedded runs in the specified
	// writing system.
	// 1a. Regular multilingual strings: MultiStr
	int cRows;
	if (m_fExactCount && m_qadvi3)
	{
		stuCmd.Format(L"SELECT COUNT(*) FROM MultiStr$ a");
		if (pszIdsTable != NULL)
			stuCmd.FormatAppend(L" JOIN %s b ON b.ObjId = a.Obj", pszIdsTable);
		CheckHr(m_qodc->ExecCommand(stuCmd.Bstr(), knSqlStmtSelectWithOneRowset));
		CheckHr(m_qodc->GetRowset(0));
		CheckHr(m_qodc->NextRow(&fMoreRows));
		CheckHr(m_qodc->GetColValue(1, reinterpret_cast<BYTE *>(&cRows),
			isizeof(int), &cbSpaceTaken, &fIsNull, 0));
	}
Exemplo n.º 3
0
/*----------------------------------------------------------------------------------------------
	Crawl through the database and rename/delete the given styles.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP FwDbMergeStyles::Process(DWORD hWnd)
{
	BEGIN_COM_METHOD;
	Assert(m_vstuOldNames.Size() == m_vstuNewNames.Size());

	if (!m_hvoRoot)
		return E_UNEXPECTED;
	if (!m_pclsidApp)
		return E_UNEXPECTED;

	if (LogFile())
	{
		ULONG cbLog;
		StrAnsi staLog;
		staLog.Format("Changing style names in %S (%S)%n",
			DbName().Chars(), ServerName().Chars());
		LogFile()->Write(staLog.Chars(), staLog.Length(), &cbLog);
	}

	m_qprog->DoModeless((HWND)hWnd);
	StrUni stuMsg(kstidChgStyleLabel);
	m_qprog->put_Title(stuMsg.Bstr());

	ResetConnection();
	BeginTrans();
	CreateCommand();

	SetPercentComplete(0);

	// We want to affect only a subset of the formatting and style information in the database,
	// based on which program is currently running, since different programs may be using
	// different sets of styles.  This information is derived from m_hvoRoot and m_pclsidApp.
	// (Unfortunately, there's no way to derive one of these values from the other one.)  The
	// current scheme works for Data Notebook, List Editor, TE, and LexText.  Additional
	// programs may introduce even more complexities.
	// 1. Find all the owners of StStyle objects.  This should match up to LangProject (Data
	//    Notebook and List Editor), Scripture (TE), or LexDb (LexText).
	// 2. If an owner equals m_hvoRoot, then only those objects owned by m_hvoRoot have the
	//    string and paragraph formatting fixed.  Except that LexText also wants to fix all the
	//    Text objects owned by the LangProject in addition to all the objects owned by the
	//    LexDb, so those have to be added to the collection of objects.
	// 3. If none of the owners equals m_hvoRoot, we must be dealing with Data Notebook or List
	//    Editor, which share a common set of styles owned by the LangProject itself.  In
	//    this case, we want all the objects owned by the LangProject except those owned by
	//    another owner of styles (or the LangProject Text objects, since those use the
	//    LexText styles even though they're not owned by the root object).  (This isn't quite
	//    right if either TE or LexText does not actually own any styles yet, but we won't worry
	//    about this nicety.)
	// 4. After creating a temp table containing just the ids of those objects of interest, we
	//    can then process all the relevant string formatting (via a string crawler) and
	//    paragraph StyleRules (later in this method)
	// 5. Finally, we may need to fix the Style fields of the relevant UserViewField objects.
	//    These are limited by the psclsidApp argument, since the UserView objects are specific
	//    to specific applications.  If pssclidApp indicates either Data Notebook or List
	//    Editor, then UserViewField objects belonging to both of those programs are fixed.
	//    Otherwise, only those UserViewField objects belonging to the specific program
	//    identified by psclsidApp are fixed.

	ComBool fMoreRows;
	UINT cbSpaceTaken;
	ComBool fIsNull;
	int hobj = 0;
	int clid = 0;
	bool fFixOwned = false;
	int clidOwned = 0;
	int hvoLangProj = 0;
	Vector<int> vhvoOwners;
	Vector<int> vclidOwners;
	Vector<int> vhvoTexts;
	StrUni stuCmd;
	stuCmd.Format(L"SELECT DISTINCT c.Owner$, co.Class$ "
		L"FROM CmObject c "
		L"JOIN CmObject co on co.Id = c.Owner$ "
		L"WHERE c.Class$ = %d",
		kclidStStyle);
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtSelectWithOneRowset));
	CheckHr(GetOleDbCommand()->GetRowset(0));
	CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	while (fMoreRows)
	{
		CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&hobj),
			isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));
		CheckHr(GetOleDbCommand()->GetColValue(2, reinterpret_cast <BYTE *>(&clid),
			isizeof(clid), &cbSpaceTaken, &fIsNull, 0));
		if (hobj == m_hvoRoot)
		{
			fFixOwned = true;
			clidOwned = clid;
		}
		else if (clid == kclidLangProject)
		{
			hvoLangProj = hobj;
		}
		else
		{
			vhvoOwners.Push(hobj);
			vclidOwners.Push(clid);
		}
		CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	}
	Assert(hvoLangProj != 0);
// This may not be defined in any of our header files.
#ifndef kclidLexDb
#define kclidLexDb 5005
#endif
	if (!fFixOwned || clidOwned == kclidLexDb)
	{
		// We need the set of LangProject_Texts objects to include or exclude.
		stuCmd.Format(L"SELECT Dst FROM LangProject_Texts WHERE Src = %d", hvoLangProj);
		CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(),
			knSqlStmtSelectWithOneRowset));
		CheckHr(GetOleDbCommand()->GetRowset(0));
		CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
		while (fMoreRows)
		{
			CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&hobj),
				isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));
			vhvoTexts.Push(hobj);
			CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
		}
	}
	// Note that dbo.fnGetOwnedObjects$() returns the root object as the first row.
	stuCmd.Format(L"CREATE TABLE #OwnedObjIdsTbl%n"
		L"(%n"
		L"    ObjId int not null%n"
		L")%n"
		L"CREATE CLUSTERED INDEX #OwnedObjIdsTblObjId ON #OwnedObjIdsTbl ([ObjId])%n");
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtNoResults));

	const OLECHAR * kpszDefTableFmt =
		L"INSERT INTO #OwnedObjIdsTbl%n"
		L"SELECT ObjId%n"
		L"FROM dbo.fnGetOwnedObjects$('%d', null, 0, 0, 1, null, 0)";

	if (fFixOwned)
	{
		stuCmd.Format(kpszDefTableFmt, m_hvoRoot);
		stuCmd.FormatAppend(L";%n");
		if (vhvoTexts.Size())
		{
			stuCmd.FormatAppend(
				L"INSERT INTO #OwnedObjIdsTbl%n"
				L"SELECT ObjId%n"
				L"FROM dbo.fnGetOwnedObjects$('");
			for (int ihvo = 0; ihvo < vhvoTexts.Size(); ++ihvo)
				if (ihvo == 0)
					stuCmd.FormatAppend(L"%d", vhvoTexts[ihvo]);
				else
					stuCmd.FormatAppend(L",%d", vhvoTexts[ihvo]);
			stuCmd.FormatAppend(L"', null, 0, 0, 1, null, 0);");
		}
	}
	else
	{
	/*
	POSSIBLE SPEED ENHANCEMENT
	--------------------------
	SELECT co.Id
	FROM CmObject co
	WHERE co.Owner$=1 AND co.OwnFlid$ NOT IN (6001006, 6001014, 6001040)

	gives a list of ids which own what we want to look through.  This could then be
	handled by the following query, which runs in one-half to one-third of the time
	required by the current code.

	SELECT 1 UNION SELECT ObjId FROM dbo.fnGetOwnedObjects$('2,54728', null, 0, 0, 1, null, 0)

	whether the C++ code or the SQL code should put together the XML string is a good
	question.
	*/
		// REVIEW (SteveMiller): The temp tables below just slow things down.

		stuCmd.Clear();
		if (vhvoOwners.Size() || vhvoTexts.Size())
		{
			stuCmd.FormatAppend(L"CREATE TABLE #tblUnwanted ( ObjId int not null );%n");
			stuCmd.FormatAppend(L"INSERT INTO #tblUnwanted%n");
			stuCmd.FormatAppend(L"SELECT ObjId%n");
			stuCmd.FormatAppend(L"FROM dbo.fnGetOwnedObjects$('");
			for (int ihvo = 0; ihvo < vhvoOwners.Size(); ++ihvo)
				if (ihvo == 0)
					stuCmd.FormatAppend(L"%d", vhvoOwners[ihvo]);
				else
					stuCmd.FormatAppend(L",%d", vhvoOwners[ihvo]);
			for (int ihvo = 0; ihvo < vhvoTexts.Size(); ++ihvo)
				if (vhvoOwners.Size() < 0)
					// I don't think we can have an ownerless text, but hey...
					stuCmd.FormatAppend(L"%d", vhvoTexts[ihvo]);
				else
					stuCmd.FormatAppend(L",%d", vhvoTexts[ihvo]);
			stuCmd.FormatAppend(L"',null,0,0,1,null,0);%n");
		}
		stuCmd.FormatAppend(kpszDefTableFmt, hvoLangProj);
		if (vhvoOwners.Size() || vhvoTexts.Size())
		{
			stuCmd.FormatAppend(L"WHERE ObjId NOT IN (SELECT ObjId FROM #tblUnwanted);%n");
			stuCmd.FormatAppend(L"DROP TABLE #tblUnwanted");
		}
		stuCmd.FormatAppend(L";%n");	// terminate for Firebird
	}
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtNoResults));

	// Do the standard stuff for monolingual and multilingual strings.
	DoAll(kstidChgStylePhaseOne, kstidChgStylePhaseTwo,
		false,	// don't create a new transaction--this method handles it
		L"#OwnedObjIdsTbl");

	// Fix all the StyleRules of instances of StPara.
	stuMsg.Load(kstidChgStylePhaseThree);
	m_qprog->put_Message(stuMsg.Bstr());

	int nPercent = 0;
	SetPercentComplete(nPercent);

	Vector<int> vhobjFix;
	Vector<Vector<byte> > vvbFmtFix;
	vhobjFix.Clear();
	vvbFmtFix.Clear();

	Vector<byte> vbFmt;
	int cbFmt;

	ITsPropsFactoryPtr qtpf;
	qtpf.CreateInstance(CLSID_TsPropsFactory);

	int cRows;
	StrUni stuCmdCnt;
	stuCmdCnt.Format(L"SELECT COUNT(*) FROM StPara a%n"
		L"JOIN #OwnedObjIdsTbl b on b.ObjId = a.Id%n"
		L"WHERE a.StyleRules IS NOT NULL",
		m_hvoRoot);
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmdCnt.Bstr(),
		knSqlStmtSelectWithOneRowset));
	CheckHr(GetOleDbCommand()->GetRowset(0));
	CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&cRows),
		isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));

	stuCmd.Format(L"SELECT a.Id, a.StyleRules FROM StPara a%n"
		L"JOIN #OwnedObjIdsTbl b on b.ObjId = a.Id%n"
		L"WHERE a.StyleRules IS NOT NULL",
		m_hvoRoot);
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtSelectWithOneRowset));
	CheckHr(GetOleDbCommand()->GetRowset(0));
	CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	int iRow = 0;
	ComVector<ITsTextProps> vqttp;
	vqttp.Resize(1);
	while (fMoreRows)
	{
		CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&hobj),
			isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));
		CheckHr(GetOleDbCommand()->GetColValue(2,
			reinterpret_cast <BYTE *>(vbFmt.Begin()), vbFmt.Size(), &cbSpaceTaken, &fIsNull,
			0));
		cbFmt = cbSpaceTaken;
		if (cbFmt >= vbFmt.Size())
		{
			vbFmt.Resize(cbFmt + 1);
			CheckHr(GetOleDbCommand()->GetColValue(2,
				reinterpret_cast <BYTE *>(vbFmt.Begin()),
				vbFmt.Size(), &cbSpaceTaken, &fIsNull, 0));
			cbFmt = cbSpaceTaken;
		}
		vbFmt.Resize(cbFmt);

		ITsTextPropsPtr qttp;
		bool fModify = false;
		int cb = vbFmt.Size();
		CheckHr(qtpf->DeserializePropsRgb(vbFmt.Begin(), &cb, (ITsTextProps **)&qttp));

		// use a vector with exactly 1 item
		vqttp[0] = qttp;
		// Note: using "Normal" doesn't work all the time. For more complex scenarios where the
		// default style depends on the context of the deleted style, a replace should be done
		// instead of a delete. See FwStylesDlg.DeleteAndRenameStylesInDB() in FwStylesDlg.cs.
		fModify = ProcessFormatting(vqttp, g_pszwStyleNormal);
		if (fModify)
		{
			vhobjFix.Push(hobj);
			int cbNeeded;
			HRESULT hr;
			CheckHr(hr = vqttp[0]->SerializeRgb(vbFmt.Begin(), vbFmt.Size(), &cbNeeded));
			if (hr == S_FALSE)
			{
				vbFmt.Resize(cbNeeded);
				hr = vqttp[0]->SerializeRgb(vbFmt.Begin(), vbFmt.Size(), &cbNeeded);
			}
			vbFmt.Resize(cbNeeded);
			vvbFmtFix.Push(vbFmt);
		}
		CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));

		iRow++;
		SetPercentComplete((iRow * 50) / cRows);
	}
	int ceFix = vhobjFix.Size();
	SetPercentComplete(50);
	for (int ieFix = 0; ieFix < ceFix; ++ieFix)
	{
		stuCmd.Format(L"UPDATE StPara SET StyleRules=? WHERE [Id] = %d", vhobjFix[ieFix]);
		// Set the parameter and execute the command.
		CheckHr(GetOleDbCommand()->SetParameter(1, DBPARAMFLAGS_ISINPUT, NULL,
			DBTYPE_BYTES, reinterpret_cast<BYTE *>(vvbFmtFix[ieFix].Begin()),
			vvbFmtFix[ieFix].Size()));
		CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtNoResults));

		SetPercentComplete(50 + ((ieFix * 50) / ceFix));
	}
	SetPercentComplete(100);

	stuCmd.Assign(L"DROP TABLE #OwnedObjIdsTbl");
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtNoResults));

	// Fix style names in the view specs.
	// SQL gives us the power to just rename all items in one query. But that
	// won't correctly handle the situation of, for instance, renaming A to B, B to C, and
	// C to A. So we fix one item at a time and then update the database.

	static const GUID clsidNotebook =	// {39886581-4DD5-11D4-8078-0000C0FB81B5}
		{ 0x39886581, 0x4DD5, 0x11D4, { 0x80, 0x78, 0x00, 0x00, 0xC0, 0xFB, 0x81, 0xB5 } };
	static GUID clsidListEditor =	// {5EA62D01-7A78-11D4-8078-0000C0FB81B5}
		{ 0x5EA62D01, 0x7A78, 0x11D4, { 0x80, 0x78, 0x00, 0x00, 0xC0, 0xFB, 0x81, 0xB5 } };

	StrUni stuBaseCmd;
	stuBaseCmd.Format(L"%nFROM UserViewField a%n"
		L"JOIN UserViewRec_Fields uf on uf.Dst = a.Id%n"
		L"JOIN UserView_Records ur on ur.Dst = uf.Src%n"
		L"JOIN UserView uv on uv.Id = ur.Src%n"
		L"WHERE a.Style IS NOT NULL AND");
	if (*m_pclsidApp == clsidNotebook || *m_pclsidApp == clsidListEditor)
	{
		Assert(!fFixOwned);
		stuBaseCmd.FormatAppend(L"%n\tuv.App in ('%g','%g')", &clsidNotebook, &clsidListEditor);
	}
	else
	{
		Assert(fFixOwned);
		stuBaseCmd.FormatAppend(L" uv.App = '%g'", m_pclsidApp);
	}
	stuMsg.Load(kstidChgStylePhaseFour);
	m_qprog->put_Message(stuMsg.Bstr());
	SetPercentComplete(0);

	OLECHAR rgch[1024];
	vhobjFix.Clear();
	Vector<StrUni> vstuFix;

	stuCmdCnt.Format(L"SELECT COUNT(*)%s", stuBaseCmd.Chars());
	CheckHr(GetOleDbCommand()->ExecCommand(stuCmdCnt.Bstr(),
		knSqlStmtSelectWithOneRowset));
	CheckHr(GetOleDbCommand()->GetRowset(0));
	CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&cRows),
		isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));

	stuCmd.Format(L"SELECT a.Id, a.Style%s", stuBaseCmd.Chars());

	CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtSelectWithOneRowset));
	CheckHr(GetOleDbCommand()->GetRowset(0));
	CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));
	iRow = 0;
	while (fMoreRows)
	{
		CheckHr(GetOleDbCommand()->GetColValue(1, reinterpret_cast <BYTE *>(&hobj),
			isizeof(hobj), &cbSpaceTaken, &fIsNull, 0));
		CheckHr(GetOleDbCommand()->GetColValue(2, reinterpret_cast <BYTE *>(*&rgch),
			isizeof(rgch), &cbSpaceTaken, &fIsNull, 0));
		int cchw = cbSpaceTaken / isizeof(OLECHAR);

		StrUni stuOld(rgch, cchw);
		StrUni stuNew;
		if (Delete(stuOld))
		{
			vstuFix.Push(L"");
			vhobjFix.Push(hobj);
		}
		else if (Rename(stuOld, stuNew))
		{
			vstuFix.Push(stuNew);
			vhobjFix.Push(hobj);
		}

		CheckHr(GetOleDbCommand()->NextRow(&fMoreRows));

		iRow++;
		SetPercentComplete((iRow * 50) / cRows);
	}
	SetPercentComplete(50);
	Assert(vhobjFix.Size() == vstuFix.Size());

	ceFix = vstuFix.Size();
	for (int ieFix = 0; ieFix < ceFix; ieFix++)
	{
		if (vstuFix[ieFix] == L"")
		{
			stuCmd.Format(L"UPDATE UserViewField SET Style = NULL where [Id] = '%d'",
				vhobjFix[ieFix]);
		}
		else
		{
			StrUtil::NormalizeStrUni(vstuFix[ieFix], UNORM_NFD);
			stuCmd.Format(L"UPDATE UserViewField SET Style = '%s' where [Id] = '%d'",
				vstuFix[ieFix].Chars(), vhobjFix[ieFix]);
		}
		CheckHr(GetOleDbCommand()->ExecCommand(stuCmd.Bstr(), knSqlStmtNoResults));

		SetPercentComplete(50 + ((ieFix * 50) / ceFix));
	}

	SetPercentComplete(100);
	CommitTrans();
	Terminate(m_hvoRoot);

	if (m_qprog)
		m_qprog->DestroyHwnd();
	END_COM_METHOD(g_fact, IID_IFwDbMergeStyles);
}