void UBTAuditLogEx(const char *szFile, const char *pzText, bool bNewLine, bool push)
{
	if (g_pchLogFile == LOGGING_UNASSIGNED)
	{
		try
		{
			g_pchLogFile = (char *)GetProfile().GetString("Debug", "DebugTraceXML",false);
			if (g_pchLogFile && g_pchLogFile[0])
			{
				// g_pchLogFile is valid and logging is turned ON
			}
			else
			{
				// Turn off logging and don't check the environment variable anymore (it's slow)
				g_pchLogFile = (char *)LOGGING_OFF;
			}
		}
		catch (GException &)
		{
		}
	}

	if (g_pchLogFile != LOGGING_OFF)
	{
		// trace out the xml being sent to the server
//		fstream fsOut(g_pchLogFile,  ios::out | ios::app);
		GString strOut;

		for (int i = 0; i < nIndent; i++)
			strOut << "   ";

		strOut << '(' << szFile << ')';

		if (push)
			strOut << " push: ";
		else
			strOut << " pop : ";

		if (pzText)
			strOut << pzText;
		else
			strOut << "(null)";

		if (bNewLine)
			strOut << "\n";
		strOut.ToFileAppend(g_pchLogFile);
	}
}
const char *XMLProcedureCall::Execute( XMLObject *pDestinatonObject /*= 0*/, 
							    bool bDestinationObjectTagPresent /* = 1*/)
{
	if (!m_DataSource)
	{
		throw GException("XMLProcedureCall", 8);
	}

	if (!m_strSchema.IsEmpty())
		AddAttribute( "Schema", (const char *)m_strSchema );

	m_DataSource->AddAttributes(this);
	if ( m_lstProcedures.Size() > 1  ||		// Multiple DB operations or joins(within the same transaction) 
		 m_bForceTransaction 		 ||		// Force Transactional
		 strstr((const char *)m_strProcedureName,"::") )	// executing CustomDLL.procedure

	{
		AddAttribute( "Transaction", "yes" );
	}

	if ( GetRowCount() != (long)-1 )
	{
		AddAttribute( "maxObjects", GetRowCount() );
	}

	if (m_pzReportTemplateName)
	{
		AddAttribute( "MergeXML", "yes" );
		AddAttribute( "Template", m_pzReportTemplateName );
	}
	
	ToXML(&m_strRequest);

	if (m_lpfnSend)
	{
		m_lpfnSend((const char *)m_strRequest);
	}

	const char *pDebugFile = GetProfile().GetString("Debug", "DebugTraceXML", false);
	if (pDebugFile && pDebugFile[0])
	{
		// trace out the xml being sent to the server
		GString strTrace;
		strTrace.Format("\n\n\n\nSent To [%s]-----------\n%s",m_DataSource->GetServerAddress(),(const char *)m_strRequest);
		strTrace.ToFileAppend(pDebugFile);
	}
	
	int nRetryCount = 0;
RESEND:
	try
	{
		
		m_strXml = m_DataSource->send(	(const char *)m_strProcedureName,
										(const char *)m_strRequest,
										(int)m_strRequest.Length(),/* Length w/o Null terminator */
										0, 
										&m_pUserData,"TransactXML=");

		if (m_lpfnRecv)
			m_lpfnRecv(m_strXml);

	}
	catch(GException &e)
	{
		// "General error parsing XML stream" means the data was corrupted in transit.
		if (e.GetError() == 7)
		{
			// Resend the request.
			if (nRetryCount++ < 3)
			{
				TRACE_WARNING("Attempting resend" );
				goto RESEND;
			}
		}
		
		// "the handle is invalid".  We need to 'reboot' the datasource. (WININET)
		if ((e.GetError()  == 6) && 
			(e.GetSystem() == 0)) 
		{
			// Resend the request.
			if (nRetryCount++ < 3)
			{
				TRACE_WARNING("Attempting resend" );
				m_DataSource->IPAddressChange();
				goto RESEND;
			}
		}

		// This helps distinguish Client errors from Server errors
		// unless the error was a client side connect error.
		throw GException("XMLProcedureCall", 4, m_DataSource->GetServerAddress(), e.GetDescription());
	}

	if (pDebugFile && pDebugFile[0])
	{
		// trace out the xml returned from the server
		GString strTrace("\n\n\n\nReceived:\n----------\n");
		const char *pXML = GetXML();
		if (pXML)
			strTrace += pXML;
		strTrace.ToFileAppend(pDebugFile);
	}

	// map to tags that we expect to recieve in the query results
	LoadMemberMappings();

	if ( m_bRunObjectFactory && m_strXml && m_strXml[0] )
	{
		const char *pFactoryXML = m_strXml;
		if (m_pzReportTemplateName)
		{
			pFactoryXML = GetXML();
		}
		
		try
		{
			if (pDestinatonObject)
			{
		
				// The tag "XMLQueryResults" can be anything.  The outer most
				// tag is never verified, this object will contain the Root
				// starting point for factorization (the pDestinatonObject object)
				if (bDestinationObjectTagPresent)
				{
					XMLRelationshipWrapper objectContainer("XMLQueryResults");

					objectContainer.ModifyObjectBehavior(PREVENT_AUTO_DESTRUCTION);


					const char *tag = pDestinatonObject->GetObjectTag();
					objectContainer.AddReference(	tag, pDestinatonObject );


					// When we are paring into an object and the object tag is
					// specified in the XML.  For example, when placing:
					// <Results>
					//		<Customer>
					//			<Widgit>
					//				...
					//			</Widgit>
					//		</Customer>
					// </Results>

					// This will allow us to put Widgit's in a 'Customer' or any 
					// type of object that the pDestinatonObject describes.
					objectContainer.FromXML(pFactoryXML,this);
				}
				else
				{
					// When we are paring into an object but that object is not
					// specified in the XML.  For example, when placing:
					// <Results>
					//		<Widgit>
					//			...
					//		</Widgit>
					// </Results>

					// This will allow us to put Widgit's in a 'Customer' or any 
					// type of object that the pDestinatonObject describes.
					pDestinatonObject->FromXML(pFactoryXML,this);
				}
			}
			else
			{
				XMLObjectFactory factory ( pFactoryXML,m_DataSource->GetServerAddress() );
				// Only Queries have result descriptors
				if ( getResultObjectTag() )
				{
					factory.setResultDescriptor( GetEntry( getResultObjectTag() ) );
				}
				factory.extractObjects(this);
			}
		}
		catch (GException &)
		{
			throw;
		}

// in a debug build, this code is better off compiled out so that the debugger will break closer to the problem.
// in a release build, this may help to 'crash softer'.
#ifndef _DEBUG
		// if we should catch an unhandled exception here
		catch ( ... )
		{
			TRACE_ERROR("Fatal Error while factory creating objects" );
			TRACE_ERROR("1. Check your String/List Handlers" );
			TRACE_ERROR("2. Did you delete a cached object and not remove it from the cache?");
	
			throw GException("XMLProcedureCall", 6);
		}
#endif

	}
	else
	{
		if (m_bRunObjectFactory)
		{
			// we should never get nothing, it may indicate 
			// communication failure depending on the type of DataSource
			TRACE_WARNING("Nothing received from DataBroker" );
			throw GException("XMLProcedureCall", 7);
		}
	}
	return m_strXml;
}