Beispiel #1
0
/*----------------------------------------------------------------------------------------------
	Initialize the database.
----------------------------------------------------------------------------------------------*/
void InitializeDB(const wchar * pszwServer, const wchar * pszwDB, const char * pszInitScript)
{
	SqlDb sdb;
	SqlStatement sstmt;
	HRESULT hr;
	char * pszCmd;
	char * psz;
	char * pchEnd;
	int chLeading;
	int chTrailing;
	Vector<char> vchScript;
	FILE * pfile;
	RETCODE rc;
	struct stat statInit;

	// osql -U sa -E -n -b -d %1 <%SQLSCRIPT%

	if (stat(pszInitScript, &statInit))
	{
		fprintf(stderr, "Cannot open Initialization SQL file \"%s\"!\n", pszInitScript);
		ThrowHr(WarnHr(E_FAIL));
	}
	vchScript.Resize(statInit.st_size + 1);
	pfile = fopen(pszInitScript, "rb");
	if (!pfile)
	{
		fprintf(stderr, "Cannot open Initialization SQL file \"%s\"!\n", pszInitScript);
		ThrowHr(WarnHr(E_FAIL));
	}
	fread(vchScript.Begin(), 1, statInit.st_size, pfile);
	fclose(pfile);
	pchEnd = vchScript.Begin() + statInit.st_size;
	*pchEnd = '\0';

	hr = sdb.Open(pszwServer, pszwDB);
	CheckHr(hr);
	sstmt.Init(sdb);

	// This is needed to allow double quotes in dynamic SQL, which is used by some of the
	// stored procedures that FieldWorks defines.
	pszCmd = "SET QUOTED_IDENTIFIER OFF";
	rc = SQLExecDirectA(sstmt.Hstmt(), reinterpret_cast<SQLCHAR *>(pszCmd), SQL_NTS);
	VerifySqlRc(rc, sstmt.Hstmt(), pszCmd);
	sstmt.Clear();

	// Find next "go" keyword, if any.
	// Note that we have to skip over any comments or quoted strings while searching.
	// Also we need to convert non-embedded double quotes to single quotes.
	bool fSingleQuoted;
	bool fDoubleQuoted;
	char * pszOpen;
	bool fInLineComment;
	bool fInsideComment;
	int ch;
	int ch2;
	for (pszCmd = vchScript.Begin(); pszCmd < pchEnd; pszCmd = psz)
	{
		// Skip leading whitespace.
		pszCmd += strspn(pszCmd, " \t\r\n\f\v");
		if (pszCmd == pchEnd)
			break;
		fSingleQuoted = false;
		fDoubleQuoted = false;
		pszOpen = NULL;
		fInLineComment = false;
		fInsideComment = false;
		for (psz = pszCmd; psz < pchEnd; ++psz)
		{
			ch = *psz;
			ch2 = *(psz + 1);
			if (fInLineComment)
			{
				if (ch == '\n')
					fInLineComment = false;
				continue;
			}
			if (fInsideComment)
			{
				if (ch == '*' && ch2 == '/')
				{
					fInsideComment = false;
					++psz;
				}
				continue;
			}
			if (!fSingleQuoted && !fDoubleQuoted)
			{
				if (ch == '-' && ch2 == '-')
				{
					fInLineComment = true;
					++psz;
					continue;
				}
				else if (ch == '/' && ch2 == '*')
				{
					fInsideComment = true;
					++psz;
					continue;
				}
			}
			if (ch == '\'')
			{
				if (fSingleQuoted)
				{
					fSingleQuoted = false;
				}
				else if (fDoubleQuoted)
				{
					// Retain outer double quotes if embedded single quote.
					pszOpen = NULL;
				}
				else
				{
					fSingleQuoted = true;
				}
			}
			else if (ch == '"')
			{
				if (fSingleQuoted)
				{
					// Do nothing. (?)
				}
				else if (fDoubleQuoted)
				{
					if (pszOpen)
					{
						// Convert double quotes to single quotes if not embedded.
						*pszOpen = '\'';
						*psz = '\'';
						pszOpen = NULL;
					}
					fDoubleQuoted = false;
				}
				else
				{
					fDoubleQuoted = true;
					pszOpen = psz;
				}
			}
			else if ((ch == 'g' || ch == 'G') && (ch2 == 'o' || ch2 == 'O') &&
				!fSingleQuoted && !fDoubleQuoted)
			{
				chLeading = (psz > pszCmd) ? *(psz - 1) : ' ';
				chTrailing = (psz + 2 < pchEnd) ? *(psz + 2) : ' ';
				if (isascii(chLeading) && isspace(chLeading) &&
					isascii(chTrailing) && isspace(chTrailing))
				{
					*psz = '\0';
					psz += 2;
					break;
				}
			}
		}

		sstmt.Init(sdb);
		rc = SQLExecDirectA(sstmt.Hstmt(), reinterpret_cast<SQLCHAR *>(pszCmd), strlen(pszCmd));
		VerifySqlRc(rc, sstmt.Hstmt(), pszCmd);
		sstmt.Clear();
	}
	sdb.Close();
}
Beispiel #2
0
/*----------------------------------------------------------------------------------------------
	Save data in the cache, to the database.
----------------------------------------------------------------------------------------------*/
STDMETHODIMP VwRsOdbcDa::Save(SqlDb & sdb)
{
	BEGIN_COM_METHOD

	const kcchErrMsgBuf = 1024;
	const kcbFmtBufMax = 1024;
	const kcchMaxColNameSize = 200;

	SQLINTEGER cbColVal;
	SDWORD cbClassName;
	long cbHvo;
	SDWORD cbFieldName;
	SDWORD cbFlid;
	int cbFmtBufSize = kcbFmtBufMax;
	int cbFmtSpaceTaken;
	SDWORD cbType;
	SQLUSMALLINT cParamsProcessed = 0;
	HRESULT hr;
	FieldMetaDataMap fmdm;		//  REVIEW PaulP:  Would be nice to have this kept globally.
	FieldMetaDataRec fmdr;
	int nColVal;
	int nFlid;
	ITsStringPtr qtssColVal;
	RETCODE rc;
	byte * rgbFmt = NewObj byte[kcbFmtBufMax]; //[kcbFmtBufMax];
	SmartBstr sbstr;
	SQLCHAR sqlchSqlState[5];
	SQLCHAR sqlchMsgTxt[kcchErrMsgBuf];
	SQLINTEGER sqlnNativeErrPtr;
	SQLSMALLINT sqlnTextLength;
	SQLRETURN sqlr;
	SqlStatement sstmt;
	StrUni suColumnName;
	StrUni suFieldMetaDataSql;
	StrUni suSql;
	StrUni suTableName;
	wchar wchClassName[kcchMaxColNameSize];
	wchar wchFieldName[kcchMaxColNameSize];


	Assert(sdb.IsOpen());


	/*------------------------------------------------------------------------------------------
		If a pointer to a HashMap of field$ metadata information was not passed in as a
		parameter, create the HashMap.  The metaData includes all field names, field types,
		class names, and destination class name from the field$ and class$ tables.
		This information is needed since only store the "flid" value is stored in the cache
		(as the "tag") so when it comes time to do SQL "insert" and "update" statements,
		one need's to know what table and column needs to be affected.

		REVIEW PaulP:  Should really cache this information globally so that it does not have
		to be reloaded each time the view cache is saved.  The only time this info would have
		to be reloaded is when custom fields are added.  Perhaps we could have a table with
		a single record which indicates the last date/time a change to the database was made.
		This could be compared with the currently loaded date each time the cache is saved to
		see if there is a need to reload the field$ meta information.  Of course, if we
		require that only one user is allowed to be connected for a custom field addition,
		this would not be necessary.

		TOxDO PaulP:  Cleanup on any error exit, including db rollback.
						CheckSqlRc(SQLEndTran(SQL_HANDLE_DBC, sdb.Hdbc(), SQL_ROLLBACK));
	------------------------------------------------------------------------------------------*/
	try
	{
		//  Set up SQL statment to obtain meta data.
		suFieldMetaDataSql.Format(
			L"select f.Id FLID, Type, f.Name FLD_NAME,"
			L" c.Name CLS_NAME"
			L" from Field$ f"
			L" join Class$ c on c.id = f.Class"
			L" order by f.id");
		sstmt.Init(sdb);
		CheckSqlRc(SQLExecDirectW(sstmt.Hstmt(), \
			const_cast<wchar *>(suFieldMetaDataSql.Chars()), SQL_NTS));

		//  Bind Columns.
		rc = SQLSetStmtAttr(sstmt.Hstmt(), SQL_ATTR_PARAMS_PROCESSED_PTR, &cParamsProcessed, 0);
		CheckSqlRc(SQLBindCol(sstmt.Hstmt(), 1, SQL_C_SLONG, &nFlid, isizeof(int),
			&cbFlid));
		CheckSqlRc(SQLBindCol(sstmt.Hstmt(), 2, SQL_C_SLONG, &fmdr.m_iType,
			isizeof(fmdr.m_iType), &cbType));
		CheckSqlRc(SQLBindCol(sstmt.Hstmt(), 3, SQL_C_WCHAR, &wchFieldName,
			kcchMaxColNameSize, &cbFieldName));
		CheckSqlRc(SQLBindCol(sstmt.Hstmt(), 4, SQL_C_WCHAR, &wchClassName,
			kcchMaxColNameSize, &cbClassName));

		//  Put info from the columns into a FieldMetaDataRec record and insert
		//  this in the FieldMetaData HashMap.
		for (;;)
		{
			rc = SQLFetch(sstmt.Hstmt());
			if (rc != SQL_SUCCESS)
				break;
			// TOxDO PaulP:  Change this so it just gets a null terminated string!!!
			fmdr.m_suFieldName.Assign(wchFieldName, kcchMaxColNameSize);
			fmdr.m_suClassName.Assign(wchClassName, kcchMaxColNameSize);
			fmdm.Insert(nFlid, fmdr);
		}
		if (rc != SQL_NO_DATA)
		{
			//  REVIEW PaulP (SteveMc): Handle possible error message?
			ThrowHr(WarnHr(E_UNEXPECTED));
		}
		sstmt.Clear();
	}
	catch (...)
	{
		sstmt.Clear();
		delete rgbFmt;
		return E_UNEXPECTED;
	}


	/*------------------------------------------------------------------------------------------
		For every key in the "m_soprMods" ObjPropSet set (ie. all the object properties
		that have been updated), look up that key in the appropriate HashMap and form an SQL
		"update" statement according to the field$ "Type".

		This begins a single database transaction.  All the data in the application view cache
		must either be inserted/updated to the database successfully or the action should fail.
		This necessitates that the database connection is in manual-commit mode.

		REVIEW PaulP:  It is probably faster to collect all the properties for a given object
		type and update the table in the database all with one SQL statement but this will
		do for now until the OLE DB stuff is done.
	------------------------------------------------------------------------------------------*/
	try
	{
		ObjPropSet::iterator itops;
		for (itops = m_soprMods.Begin(); itops != m_soprMods.End(); ++itops)
		{
			//  Get the oprKey from the "update object property" Set.
			ObjPropRec & oprKey = itops.GetValue();

			//  Get the field$ metadata information based on the tag of that oprKey.
			fmdm.Retrieve(oprKey.m_tag, &fmdr);

			//  Initialize and form the SQL statment based on the field "type".
			sstmt.Init(sdb);
			switch (fmdr.m_iType)
			{
				case kcptNil:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;

				case kcptBoolean:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;

				case kcptInteger:
					//  Prepare the SQL statement.  (Uses parameters).
					suSql.Format(L"update %s set %s=? where id=?", fmdr.m_suClassName.Chars(),
						fmdr.m_suFieldName.Chars());
					rc = SQLPrepareW(sstmt.Hstmt(), const_cast<wchar *>(suSql.Chars()),
						SQL_NTS);

					//  Get the integer value from the appropriate HashMap.
					if (m_hmoprn.Retrieve(oprKey, &nColVal))
					{
						//  Bind integer value as the first parameter.
						if (nColVal)
						{
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_SLONG, SQL_INTEGER, 0, 0, &nColVal, 0, &cbColVal);
						}
						else
						{
							// REVIEW JohnT:  How do we indicate in the HashMap that the user
							//		wants to set an integer to NULL?
							cbColVal = SQL_NULL_DATA;
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_SLONG, SQL_INTEGER, 0, 0, NULL, 0, &cbColVal);
						}

						//  Bind the HVO (Id) as the second parameter.
						rc = SQLBindParameter(sstmt.Hstmt(), 2, SQL_PARAM_INPUT,
							SQL_C_SLONG, SQL_INTEGER, 0, 0, &(oprKey.m_hvo), 0, &cbHvo);
					}
					else
					{
						ThrowHr(WarnHr(E_UNEXPECTED));
					}
					break;


				case kcptNumeric:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptFloat:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptTime:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptGuid:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptImage:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptGenDate:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptBinary:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;


				case kcptString:
				case kcptBigString:

					//  Prepare the SQL statement.  (Uses parameters.)
					//  REVIEW PaulP:  Should I be hard-coding "_Fmt" in like this?
					suSql.Format(L"update %s set %s=?, %s_Fmt=? where id=?",
						fmdr.m_suClassName.Chars(), fmdr.m_suFieldName.Chars(),
						fmdr.m_suFieldName.Chars());
					rc = SQLPrepareW(sstmt.Hstmt(), const_cast<wchar *>(suSql.Chars()),
						SQL_NTS);

					if (m_hmoprtss.Retrieve(oprKey, qtssColVal))
					{
						//  Obtain a SmartBstr from the COM smart pointer that points
						//  to the TsString.
						CheckHr(qtssColVal->get_Text(&sbstr));
						if (sbstr.Length())
						{
							//  Copy format information of the TsString to byte array rgbFmt.
							hr = qtssColVal->SerializeFmtRgb(rgbFmt, cbFmtBufSize,
								&cbFmtSpaceTaken);
							if (hr != S_OK)
							{
								if (hr == S_FALSE)
								{
									//  If the supplied buffer is too small, try it again with
									//  the value that cbFmtSpaceTaken was set to.  If this
									//   fails, throw error.
									delete rgbFmt;
									rgbFmt = NewObj byte[cbFmtSpaceTaken];
									cbFmtBufSize = cbFmtSpaceTaken;
									CheckHr(qtssColVal->SerializeFmtRgb(rgbFmt, cbFmtBufSize,
										&cbFmtSpaceTaken));
								}
								else
								{
									ThrowHr(WarnHr(E_UNEXPECTED));
								}
							}

							//  Bind the text and format parts of the string to the parameters.
							SQLINTEGER cbTextPart = sbstr.Length() * 2;
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_WCHAR, SQL_WVARCHAR, cbTextPart, 0,
								const_cast<wchar *>(sbstr.Chars()), cbTextPart, &cbTextPart);
							SQLINTEGER cbFmtPart = cbFmtSpaceTaken;
							rc = SQLBindParameter(sstmt.Hstmt(), 2, SQL_PARAM_INPUT,
								SQL_C_BINARY, SQL_VARBINARY, cbFmtPart, 0, rgbFmt, cbFmtPart,
								&cbFmtPart);
						}
						else
						{
							//  Since the string had no length, bind NULL to the parameters.
							SQLINTEGER cbTextPart = SQL_NULL_DATA;
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_WCHAR, SQL_WVARCHAR, 1, 0, NULL, 0, &cbTextPart);
							//  REVIEW PaulP:  Should we set the Fmt info to NULL for NULL
							//     strings or should we use the Fmt info returned from the
							//     TsString?
							SQLINTEGER cbFmtPart = SQL_NULL_DATA;
							rc = SQLBindParameter(sstmt.Hstmt(), 2, SQL_PARAM_INPUT,
								SQL_C_BINARY, SQL_VARBINARY, 1, 0, NULL, 0, &cbFmtPart);
						}
					}
					else
					{
						ThrowHr(WarnHr(E_UNEXPECTED));
					}

					//  Bind the HVO (ie. Id) value.
					rc = SQLBindParameter(sstmt.Hstmt(), 3, SQL_PARAM_INPUT, SQL_C_SLONG,
						SQL_INTEGER, 0, 0, &(oprKey.m_hvo), 0, &cbHvo);
					break;


				case kcptBigUnicode:
				case kcptUnicode:

					//  Prepare the SQL statement.  (Uses parameters.)
					suSql.Format(L"update %s set %s=? where id=?", fmdr.m_suClassName.Chars(),
						fmdr.m_suFieldName.Chars());
					rc = SQLPrepareW(sstmt.Hstmt(), const_cast<wchar *>(suSql.Chars()),
						SQL_NTS);

					if (m_hmoprtss.Retrieve(oprKey, qtssColVal))
					{
						//  Obtain a SmartBstr from the COM smart pointer that
						//  points to a TsString.
						CheckHr(qtssColVal->get_Text(&sbstr));
						if (sbstr.Length())
						{
							//  Bind the string parameter.
							SQLINTEGER cbTextPart = sbstr.Length() * 2;
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_WCHAR, SQL_WVARCHAR, cbTextPart, 0,
								const_cast<wchar *>(sbstr.Chars()), cbTextPart, &cbTextPart);
						}
						else
						{
							//  If the string had no length, bind NULL to the parameter.
							SQLINTEGER cbTextPart = SQL_NULL_DATA;
							rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
								SQL_C_WCHAR, SQL_WVARCHAR, 1, 0, NULL, 0, &cbTextPart);
						}
					}
					else
					{
						ThrowHr(WarnHr(E_UNEXPECTED));
					}

					//  Bind the HVO (ie. Id) value.
					rc = SQLBindParameter(sstmt.Hstmt(), 2, SQL_PARAM_INPUT, SQL_C_SLONG,
						SQL_INTEGER, 0, 0, &(oprKey.m_hvo), 0, &cbHvo);
					break;

				case kcptOwningAtom:
					//  Update owning field.
					//  Update Owner$ object of CmObject.
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptReferenceAtom:
					//  This is basically the same as the Integer case except we obtain the
					//  value from the m_hmoprobj HashMap rather than the m_hmoprn HashMap.
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptOwningCollection:
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptReferenceCollection:
					//  Affect the joiner table.
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptOwningSequence:
					//  Need to update.
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				case kcptReferenceSequence:
					//  Affect the joiner table.
					ThrowHr(WarnHr(E_NOTIMPL));
					break;
				default:
					ThrowHr(WarnHr(E_UNEXPECTED));
					break;
			}

			//  Execute the SQL update command.
			//rc = SQLSetStmtAttr(sstmt.Hstmt(), SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
			rc = SQLExecute(sstmt.Hstmt());
			if (rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO)
			{
				//  TOxDO PaulP:  Error information can be obtained from sqlchMsgTxt.
				sqlr = SQLGetDiagRec(SQL_HANDLE_STMT, sstmt.Hstmt(), 1, sqlchSqlState,
					&sqlnNativeErrPtr, sqlchMsgTxt, kcchErrMsgBuf, &sqlnTextLength);
				ThrowHr(WarnHr(E_UNEXPECTED));
			}
			sstmt.Clear();
		}


		/*--------------------------------------------------------------------------------------
			Go through the m_soperMods ObjPropSet set and update columns in the MultiX tables.
		--------------------------------------------------------------------------------------*/
		ObjPropEncSet::iterator itopes;
		for (itopes = m_soperMods.Begin(); itopes != m_soperMods.End(); ++itopes)
		{
			//  Get the operKey from the "update MSA" Set.
			ObjPropEncRec & operKey = itopes.GetValue();

			//  Get the field$ metadata information based on the tag of that operKey.
			fmdm.Retrieve(operKey.m_tag, &fmdr);

			//  Initialize and form the SQL statment.
			sstmt.Init(sdb);
			if (m_hmopertss.Retrieve(operKey, qtssColVal))
			{
				//  Obtain a SmartBstr from the COM smart pointer that points to the TsString.
				CheckHr(qtssColVal->get_Text(&sbstr));
				if (sbstr.Length())
				{
					//  Get the format of the TsString
					hr = qtssColVal->SerializeFmtRgb(rgbFmt, cbFmtBufSize, &cbFmtSpaceTaken);
					if (hr != S_OK)
					{
						if (hr == S_FALSE)
						{
							//  If the supplied buffer is too small, try it again with the value
							//  that cbFmtSpaceTaken was set to.  If this fails, signal error.
							delete rgbFmt;
							rgbFmt = NewObj byte[cbFmtSpaceTaken];
							cbFmtBufSize = cbFmtSpaceTaken;
							CheckHr(qtssColVal->SerializeFmtRgb(rgbFmt, cbFmtBufSize,
								&cbFmtSpaceTaken));
						}
						else
						{
							ThrowHr(WarnHr(E_UNEXPECTED));
						}
					}

					//  Execute stored procedure to set MSA value.
					//  REVIEW PaulP:  This technique isn't going to work for custom fields
					//		since there will likely not be any "Set" stored procedure.
					suSql.Format(L"exec Set_%s_%s %d, %d, ?, ?", fmdr.m_suClassName.Chars(),
						fmdr.m_suFieldName.Chars(), operKey.m_hvo, operKey.m_ws);
					rc = SQLPrepareW(sstmt.Hstmt(), const_cast<wchar *>(suSql.Chars()),
						SQL_NTS);

					//  Bind the text and format parts of the string to the parameters.
					SQLINTEGER cbTextPart = sbstr.Length() * 2;
					rc = SQLBindParameter(sstmt.Hstmt(), 1, SQL_PARAM_INPUT,
						SQL_C_WCHAR, SQL_WVARCHAR, cbTextPart, 0,
						const_cast<wchar *>(sbstr.Chars()), cbTextPart, &cbTextPart);

					SQLINTEGER cbFmtPart = cbFmtSpaceTaken;
					rc = SQLBindParameter(sstmt.Hstmt(), 2, SQL_PARAM_INPUT, SQL_C_BINARY,
					SQL_VARBINARY, cbFmtPart, 0, rgbFmt, cbFmtPart, &cbFmtPart);
				}
				else
				{
					//  REVIEW PaulP:  This technique isn't going to work for custom fields
					//		since there will likely not be any "Set" stored procedure.
					suSql.Format(L"exec Set_%s_%s %d, %d, NULL, NULL",
						fmdr.m_suClassName.Chars(), fmdr.m_suFieldName.Chars(), operKey.m_hvo,
						operKey.m_ws);
					rc = SQLPrepareW(sstmt.Hstmt(), const_cast<wchar *>(suSql.Chars()),
						SQL_NTS);
				}

				//  Execute the SQL update command.
				//rc = SQLSetStmtAttr(sstmt.Hstmt(), SQL_ATTR_PARAM_BIND_TYPE, SQL_PARAM_BIND_BY_COLUMN, 0);
				rc = SQLExecute(sstmt.Hstmt());
				if (rc == SQL_ERROR || rc == SQL_SUCCESS_WITH_INFO)
				{
					//  TOxDO PaulP:  Error information can be obtained from sqlchMsgTxt.
					sqlr = SQLGetDiagRec(SQL_HANDLE_STMT, sstmt.Hstmt(), 1, sqlchSqlState,
						&sqlnNativeErrPtr, sqlchMsgTxt, kcchErrMsgBuf, &sqlnTextLength);
					ThrowHr(WarnHr(E_UNEXPECTED));
				}
				sstmt.Clear();
			}
			else
			{
				ThrowHr(WarnHr(E_UNEXPECTED));
			}
		}


		/*--------------------------------------------------------------------------------------
			Commit the database transaction.
			REVIEW PaulP:  The DataSource MUST be in manual commit mode.
		--------------------------------------------------------------------------------------*/
		CheckSqlRc(SQLEndTran(SQL_HANDLE_DBC, sdb.Hdbc(), SQL_COMMIT));

	}
	catch (...)
	{
		sstmt.Clear();
		delete rgbFmt;
		CheckSqlRc(SQLEndTran(SQL_HANDLE_DBC, sdb.Hdbc(), SQL_ROLLBACK));
		return E_UNEXPECTED;
	}


	/*------------------------------------------------------------------------------------------
		Clear the two Sets containing records of modified properties and MBA's.
	------------------------------------------------------------------------------------------*/
	m_soprMods.Clear();
	m_soperMods.Clear();
	delete rgbFmt; // REVIEW: Shouldn't this be delete[]?

	return S_OK;

	END_COM_METHOD(g_fact, IID_IVwCacheDa);
}
Beispiel #3
0
/*----------------------------------------------------------------------------------------------
	Create the database.  Return 0 if successful, or a nonzero value if an error occurs.
----------------------------------------------------------------------------------------------*/
int CreateDB(const char * pszServer, const char * pszDB, const char * pszOutputDir,
	const char * pszInitScript,	bool fForceCreate)
{
	HRESULT hr;

	static const wchar szwMaster[] = L"master";
	StrUniBuf stubServer(pszServer);
	StrUniBuf stubDatabase(pszDB);

	if (stubServer.Overflow() || stubDatabase.Overflow())
	{
		fprintf(stderr, "Out of memory filling static buffers??\n");
		return __LINE__;
	}
	try
	{
		SqlDb sdb;
		SqlStatement sstmt;
		StrAnsiBufBig stabCmd;
		hr = sdb.Open(stubServer.Chars(), stubDatabase.Chars());
		if (SUCCEEDED(hr))
		{
			sdb.Close();
			if (fForceCreate)
			{
				// osql /U sa /E /n /b /Q "DROP DATABASE %1"
				hr = sdb.Open(stubServer.Chars(), szwMaster);
				if (FAILED(hr))
					ThrowHr(WarnHr(hr));
				sstmt.Init(sdb);
				stabCmd.Format("DROP DATABASE %s", pszDB);
				RETCODE rc;
				rc = SQLExecDirectA(sstmt.Hstmt(),
					reinterpret_cast<SQLCHAR *>(const_cast<char *>(stabCmd.Chars())), SQL_NTS);
				VerifySqlRc(rc, sstmt.Hstmt(), stabCmd.Chars());
				sstmt.Clear();
				sdb.Close();
			}
			else
			{
				fprintf(stderr, "The database \"%s\" already exists on the server \"%s\".\n",
					pszDB, pszServer);
				fprintf(stderr,
					"Use the -f command line flag to force recreating this database.\n");
				return 1;
			}
		}
		// osql -U sa -E -n -b -Q "CREATE DATABASE %1 ON
		// (NAME=%1,FILENAME='%OUTPUT_DIR%\%1.mdf',FILEGROWTH=5MB) LOG ON
		// (NAME='%1_Log', FILENAME='%OUTPUT_DIR%\%1_log.ldf',FILEGROWTH=5MB)"
		hr = sdb.Open(stubServer.Chars(), szwMaster);
		CheckHr(hr);
		sstmt.Init(sdb);
		if (pszOutputDir)
			stabCmd.Format("CREATE DATABASE %s ON (NAME='%s',FILENAME='%s\\%s.mdf') \
LOG ON (NAME='%s_Log',FILENAME='%s\\%s_log.ldf')",
			pszDB, pszDB, pszOutputDir, pszDB, pszDB, pszOutputDir, pszDB);
		else
			stabCmd.Format("CREATE DATABASE %s ", pszDB);

		RETCODE rc;
		rc = SQLExecDirectA(sstmt.Hstmt(),
			reinterpret_cast<SQLCHAR *>(const_cast<char *>(stabCmd.Chars())), SQL_NTS);
		VerifySqlRc(rc, sstmt.Hstmt(), stabCmd.Chars());
		sstmt.Clear();
		sdb.Close();
		if (pszInitScript)
		{
			InitializeDB(stubServer.Chars(), stubDatabase.Chars(), pszInitScript);
		}
	}
	catch (Throwable & thr)
	{
		fprintf(stderr, "Error %s caught creating database \"%s\" on server \"%s\"!\n",
			AsciiHresult(thr.Error()), pszDB, pszServer);
		return __LINE__;
	}
	catch (...)
	{
		fprintf(stderr, "Error caught creating database \"%s\" on server \"%s\"!\n",
			pszDB, pszServer);
		return __LINE__;
	}
	return 0;
}