Click here to Skip to main content
15,881,248 members
Articles / Database Development / SQL Server

PostgreSQL/libpqxx Class Generator

Rate me:
Please Sign up or sign in to vote.
4.87/5 (15 votes)
18 Aug 200627 min read 82.5K   1.9K   37  
Automated generation of PostgreSQL data transfer classes.
#include "stdafx.h"
#include <atlcurr.h>
#include <comutil.h>

/////////////////////////////////////////////////////////////////////////////
// COleCurrency class (internally currency is 8-byte int scaled by 10,000)
// This was taken from olevar.cpp in the atlmfc/src/mfc directory.

const COleCurrency COleCurrency::zero(0, 0);

COleCurrency::COleCurrency(long nUnits, long nFractionalUnits)
{
	SetCurrency(nUnits, nFractionalUnits);
	SetStatus(valid);
}

const COleCurrency& COleCurrency::operator=(CURRENCY cySrc)
{
	m_cur = cySrc;
	SetStatus(valid);
	return *this;
}

const COleCurrency& COleCurrency::operator=(const COleCurrency& curSrc)
{
	m_cur = curSrc.m_cur;
	m_status = curSrc.m_status;
	return *this;
}

const COleCurrency& COleCurrency::operator=(const VARIANT& varSrc)
{
	if (varSrc.vt != VT_CY)
	{
		//try
		{
			_variant_t varTemp(varSrc);
			varTemp.ChangeType(VT_CY);
			m_cur = varTemp.cyVal;
			SetStatus(valid);
		}
		// Catch COleException from ChangeType, but not CMemoryException
		//catch (_com_error& e)
		//{
		//	// Not able to convert VARIANT to CURRENCY
		// m_cur.int64 = 0;
		//	SetStatus(invalid);
		//	DELETE_EXCEPTION(e);
		//}
		//END_CATCH
	}
	else
	{
		m_cur = varSrc.cyVal;
		SetStatus(valid);
	}

	return *this;
}

BOOL COleCurrency::operator<(const COleCurrency& cur) const
{
	ATLASSERT(GetStatus() == valid);
	ATLASSERT(cur.GetStatus() == valid);

   return (m_cur.int64 < cur.m_cur.int64);
}

BOOL COleCurrency::operator>(const COleCurrency& cur) const
{
	ATLASSERT(GetStatus() == valid);
	ATLASSERT(cur.GetStatus() == valid);

   return (m_cur.int64 > cur.m_cur.int64);
}

BOOL COleCurrency::operator<=(const COleCurrency& cur) const
{
	ATLASSERT(GetStatus() == valid);
	ATLASSERT(cur.GetStatus() == valid);

   return (m_cur.int64 <= cur.m_cur.int64);
}

BOOL COleCurrency::operator>=(const COleCurrency& cur) const
{
	ATLASSERT(GetStatus() == valid);
	ATLASSERT(cur.GetStatus() == valid);

   return (m_cur.int64 >= cur.m_cur.int64);
}

COleCurrency COleCurrency::operator+(const COleCurrency& cur) const
{
	COleCurrency curResult;

	// If either operand Null, result Null
	if (GetStatus() == null || cur.GetStatus() == null)
	{
		curResult.SetStatus(null);
		return curResult;
	}

	// If either operand Invalid, result Invalid
	if (GetStatus() == invalid || cur.GetStatus() == invalid)
	{
		curResult.SetStatus(invalid);
		return curResult;
	}

	// Add separate CURRENCY components
   curResult.m_cur.int64 = m_cur.int64+cur.m_cur.int64;

	// Overflow if operands same sign and result sign different
	if (!((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
		((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
	{
		curResult.SetStatus(invalid);
	}

	return curResult;
}

COleCurrency COleCurrency::operator-(const COleCurrency& cur) const
{
	COleCurrency curResult;

	// If either operand Null, result Null
	if (GetStatus() == null || cur.GetStatus() == null)
	{
		curResult.SetStatus(null);
		return curResult;
	}

	// If either operand Invalid, result Invalid
	if (GetStatus() == invalid || cur.GetStatus() == invalid)
	{
		curResult.SetStatus(invalid);
		return curResult;
	}

	// Subtract separate CURRENCY components
   curResult.m_cur.int64 = m_cur.int64-cur.m_cur.int64;

	// Overflow if operands not same sign and result not same sign
	if (((m_cur.Hi ^ cur.m_cur.Hi) & 0x80000000) &&
		((m_cur.Hi ^ curResult.m_cur.Hi) & 0x80000000))
	{
		curResult.SetStatus(invalid);
	}

	return curResult;
}

COleCurrency COleCurrency::operator-() const
{
	// If operand not Valid, just return
	if (!GetStatus() == valid)
		return *this;

	COleCurrency curResult;

	// Negating MIN_CURRENCY,will set invalid
   if (m_cur.int64 == _I64_MIN)
	{
		curResult.SetStatus(invalid);
	}

   curResult.m_cur.int64 = -m_cur.int64;

	return curResult;
}

COleCurrency COleCurrency::operator*(long nOperand) const
{
	// If operand not Valid, just return
	if (GetStatus() != valid)
		return *this;

	COleCurrency curResult(m_cur);

	// Return now if one operand is 0 (optimization)
   if ((m_cur.int64 == 0) || (nOperand == 0))
	{
		curResult.m_cur.int64 = 0;
		return curResult;
	}

   ULONGLONG nAbsCur;  // |m_cur.int64|
	ULONG nAbsOp;  // |nOperand|
   ULONGLONG nTempHi;  // Product of nAbsOp and high-order 32 bits of nAbsCur
   ULONGLONG nTempLo;  // Product of nAbsOp and low-order 32 bits of nAbsCur
   ULONGLONG nTempProduct;  // Sum of both partial products
   bool bProductNegative;
   bool bOverflow;

   if((nOperand^m_cur.Hi)&0x80000000)
   {
	  bProductNegative = true;
   }
   else
   {
	  bProductNegative = false;
   }
   bOverflow = false;

	// Compute absolute values.
   nAbsCur = (m_cur.int64 < 0) ? -m_cur.int64 : m_cur.int64;
	nAbsOp = labs(nOperand);

   // Compute the high-order partial product
   nTempHi = (nAbsCur>>32)*nAbsOp;
   if(nTempHi > (ULONGLONG(LONG_MAX)+1))
   {
	  // High-order multiplication overflowed
	  bOverflow = true;
   }
   else
   {
	  // Compute the low-order partial product.  Since nAbsOp is no larger 
	  // than 2**31, this multiplication can't overflow.
	  nTempLo = ULONGLONG(ULONG(nAbsCur))*nAbsOp;

	  // Sum the two partial products
	  nTempProduct = nTempLo+(nTempHi<<32);
	  if(nTempProduct < nTempLo)
	  {
		 // The sum overflowed the 64-bit result
		 bOverflow = true;
	  }
	  else
	  {
		 // At this point, nTempProduct may be still be out of range of a 
		 // positive signed 64-bit integer, but we do know that we haven't 
		 // overflowed out of our unsigned 64-bit integer variable.  
		 // If nTempProduct is greater than _I64_MAX, it will appear to be
		 // a negative signed 64-bit integer, so our result will appear to
		 // have the wrong sign.  The special case of nTempProduct == 
		 // -_I64_MIN works correctly, since negating that number is a NOP.
		 // That will

		 // Try to give the result the correct sign.
		 if(bProductNegative)
		 {
			curResult.m_cur.int64 = -LONGLONG(nTempProduct);
			// Possible cases:
			//   a) nTempProduct <= _I64_MAX: No problem.
			//   b) nTempProduct > -_I64_MIN: The result of the negation will 
			//      be positive, which will fail our check for the correct
			//      sign (which we'll do below).
			//   c) nTempProduct == -I64_MIN: The result of the negation will
			//      be _I64_MIN, which is the correct result.
		 }
		 else
		 {
			curResult.m_cur.int64 = nTempProduct;
			// Possible cases:
			//   a) nTempProduct <= _I64_MAX: No problem.
			//   b) nTempProduct > _I64_MAX: The result of the signed result
			//      will be negative, which will fail our check for the 
			//      correct sign (which we'll do below).
		 }
		 if((curResult.m_cur.Hi^m_cur.Hi^nOperand)&0x80000000)
		 {
			// The sign of the result isn't what we wanted, so there must have
			// been an overflow.
			bOverflow = true;
		 }
	  }
   }

   if(bOverflow)
   {
	  curResult.SetStatus(invalid);
	  if(bProductNegative)
	  {
		 curResult.m_cur.int64 = _I64_MIN;
	  }
	  else
	  {
		 curResult.m_cur.int64 = _I64_MAX;
	  }
   }

	return curResult;
}

COleCurrency COleCurrency::operator/(long nOperand) const
{
	// If operand not Valid, just return
	if (!GetStatus() == valid)
		return *this;

	COleCurrency curResult;

	// Check for divide by 0
	if (nOperand == 0)
	{
		curResult.SetStatus(invalid);

		// Set to maximum negative value
	  curResult.m_cur.int64 = _I64_MIN;

		return curResult;
	}

   // Check for MIN_CURRENCY/-1
   if ((nOperand == -1) && (m_cur.int64 == _I64_MIN))
   {
	  curResult.SetStatus(invalid);

	  curResult.m_cur.int64 = _I64_MAX;

	  return curResult;
   }

   curResult.m_cur.int64 = m_cur.int64/nOperand;

	return curResult;
}

void COleCurrency::SetCurrency(long nUnits, long nFractionalUnits)
{
	COleCurrency curUnits;              // Initializes to 0
	COleCurrency curFractionalUnits;    // Initializes to 0

	// Set temp currency value to Units (need to multiply by 10,000)
	curUnits.m_cur.Lo = (DWORD)labs(nUnits);
	curUnits = curUnits * 10000;
	if (nUnits < 0)
		curUnits = -curUnits;

	curFractionalUnits.m_cur.Lo = (DWORD)labs(nFractionalUnits);
	if (nFractionalUnits < 0)
		curFractionalUnits = -curFractionalUnits;

	// Now add together Units and FractionalUnits
	*this = curUnits + curFractionalUnits;

	SetStatus(valid);
}

BOOL COleCurrency::ParseCurrency(LPCTSTR lpszCurrency,
	DWORD dwFlags,  LCID lcid)
{
	USES_CONVERSION;
	CString strCurrency = lpszCurrency;

	SCODE sc = VarCyFromStr((LPOLESTR)T2COLE(strCurrency), lcid, dwFlags, &m_cur);
	if (FAILED(sc))
	{
		if (sc == DISP_E_TYPEMISMATCH)
		{
			// Can't convert string to CURRENCY, set 0 & invalid
			m_cur.int64 = 0;
			SetStatus(invalid);
			return FALSE;
		}
		else if (sc == DISP_E_OVERFLOW)
		{
			// Can't convert string to CURRENCY, set max neg & invalid
			m_cur.int64 = _I64_MIN;
			SetStatus(invalid);
			return FALSE;
		}
		//else
		//{
		//	TRACE(traceOle, 0, "\nCOleCurrency VarCyFromStr call failed.\n\t");
		//	if (sc == E_OUTOFMEMORY)
		//		AfxThrowMemoryException();
		//	else
		//		AfxThrowOleException(sc);
		//}
	}

	SetStatus(valid);
	return TRUE;
}

CString COleCurrency::Format(DWORD dwFlags, LCID lcid) const
{
	USES_CONVERSION;
	CString strCur;

	// If null, return empty string
	if (GetStatus() == null)
	{
		return strCur;
	}

	// If invalid, return Currency resource string
	if (GetStatus() == invalid)
	{
		return "Invalid Currency Value.";
	}

	_variant_t var;

	// Don't need to trap error. Should not fail due to type mismatch
	VarBstrFromCy(m_cur, lcid, dwFlags, &V_BSTR(&var));
	var.vt = VT_BSTR;
	return OLE2CT(V_BSTR(&var));
}

// This is a really quick and dirty formatter that converts the
// currency value to float, and then uses the mask in a common
// or garden sprintf.
CString COleCurrency::Format(LPCTSTR lpszMask) const
{
	CString ret = "Invalid Currency Value.";
	if (GetStatus() == valid)
	{
		char* buf = new char[strlen(lpszMask) + 30];
		double dVal = (double)(m_cur.int64 % 10000);
		dVal /= 10000.0;
		dVal += m_cur.int64 / 10000;
		sprintf(buf, lpszMask, dVal);
		ret = buf;
		delete[] buf;
	}
	return ret;
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Australia Australia
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions