// @(#)root/sapdb:$Name:  $:$Id: TSapDBRow.cxx,v 1.4 2004/06/25 12:53:18 rdm Exp $
// Author: Mark Hemberger & Fons Rademakers   03/08/2001

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#include "TString.h"
#include "TSapDBRow.h"


ClassImp(TSapDBRow)

//______________________________________________________________________________
TSapDBRow::TSapDBRow(SQLHSTMT result, Int_t nfields)
{
   // Single row of query result.

   fResult      = result;
   fFieldCount  = nfields;
   fFieldLength = 0;
   fFieldValue  = 0;
}

//______________________________________________________________________________
TSapDBRow::~TSapDBRow()
{
   // Destroy row object.

   if (fResult)
      Close();
}

//______________________________________________________________________________
void TSapDBRow::Close(Option_t *)
{
   // Close row.

   delete [] fFieldLength;
   delete [] fFieldValue;
   fResult      = 0;
   fFieldCount  = 0;
   fFieldLength = 0;
   fFieldValue  = 0;
}

//______________________________________________________________________________
Bool_t TSapDBRow::IsValid(Int_t field)
{
   // Check if row is open and field index within range.

   if (field < 0 || field >= fFieldCount) {
      Error("IsValid", "field index out of bounds");
      return kFALSE;
   }

   return kTRUE;
}

//______________________________________________________________________________
ULong_t TSapDBRow::GetFieldLength(Int_t field)
{
   // Get length in bytes of specified field.

   if (!IsValid(field))
      return 0;

   if (!fFieldLength) {
      fFieldLength = new ULong_t[fFieldCount];
      for (int i = 0; i < fFieldCount; i++)
         fFieldLength[i] = 0;
   }

   if (fFieldLength[field])
      return fFieldLength[field];

   SQLUSMALLINT columnNumber;
   SQLCHAR      columnName[256];
   SQLSMALLINT  bufferLength = 256;
   SQLSMALLINT  nameLength;
   SQLSMALLINT  dataType;
   SQLUINTEGER  columnSize;
   SQLSMALLINT  decimalDigits;
   SQLSMALLINT  nullable;

   columnNumber = field + 1;
   if (SQLDescribeCol(fResult, columnNumber, columnName, bufferLength,
                      &nameLength, &dataType, &columnSize, &decimalDigits,
                      &nullable) == SQL_SUCCESS) {
      fFieldLength[field] = columnSize;
      return columnSize;
   } else {
      Error("GetFieldLength", "cannot get field length");
      return 0;
   }
}

//______________________________________________________________________________
const char *TSapDBRow::GetField(Int_t field)
{
   // Get specified field from row (0 <= field < GetFieldCount()).

   if (!IsValid(field))
      return 0;

   if (!fFieldValue)
      fFieldValue = new TString[fFieldCount];

   if (!fFieldValue[field].IsNull())
      return fFieldValue[field];

   SQLUSMALLINT columnNumber;
   SQLCHAR      columnName[256];
   SQLSMALLINT  bufferLength = 256;
   SQLSMALLINT  nameLength;
   SQLSMALLINT  dataType;
   SQLUINTEGER  columnSize;
   SQLSMALLINT  decimalDigits;
   SQLSMALLINT  nullable;

   columnNumber = field + 1;
   RETCODE rc;
   rc = SQLDescribeCol(fResult, columnNumber, columnName, bufferLength,
                       &nameLength, &dataType, &columnSize, &decimalDigits,
                       &nullable);
   if (rc != SQL_SUCCESS) {
      Error("TSapDBRow", "error in getting description");
      return 0;
   }

   if (columnSize > 4000) {
      Error("TSapDBRow", "column size too large for current implementation.");
      return 0;
   }

   SQLINTEGER strLenOrIndPtr;
   SQLPOINTER targetValuePtr[4000];
   bufferLength = sizeof(targetValuePtr);

   if (SQLGetData(fResult, columnNumber, SQL_C_DEFAULT, targetValuePtr,
                  bufferLength, &strLenOrIndPtr) != SQL_SUCCESS) {
      Error("TSapDBRow", "error in getting data");
      return 0;
   }

   char fieldstr[4001];

   switch (dataType) {
      case SQL_CHAR:
      case SQL_VARCHAR:
      case SQL_LONGVARCHAR:
      // not yet supported...
      //case SQL_WCHAR:
      //case SQL_WVARCHAR:
      //case SQL_WLONGVARCHAR:
         sprintf(fieldstr, "%-*.*s", (int)columnSize, (int)columnSize,
                 (char*) targetValuePtr);
         break;
      case SQL_TINYINT:
      case SQL_SMALLINT:
      case SQL_INTEGER:
      case SQL_BIGINT:
         sprintf(fieldstr, "%-*ld", (int)columnSize, *(long int*)(targetValuePtr));
         break;
      case SQL_DECIMAL:
      case SQL_NUMERIC:
      case SQL_REAL:
      case SQL_FLOAT:
         sprintf(fieldstr, "%-*.2f", (int)columnSize, *(float*)(targetValuePtr));
         break;
      case SQL_DOUBLE:
         sprintf(fieldstr, "%-*.2f", (int)columnSize, *(double*)(targetValuePtr));
         break;
      case SQL_BIT:
      case SQL_BINARY:
      case SQL_VARBINARY:
      case SQL_LONGVARBINARY:
      case SQL_TYPE_DATE:
      case SQL_TYPE_TIME:
      case SQL_TYPE_TIMESTAMP:
      default:
         sprintf(fieldstr, "%-*.*s", (int)columnSize, (int)columnSize,
                 (char*)targetValuePtr);
         break;
   }

   fFieldValue[field] = fieldstr;

   return fFieldValue[field];
}
