#include "table.h"
#include <cstdio>
/* The constructor initialises its members. */
Table::Table()
{ tab.colNum = 0; tab.colName = "<empty>";
tab.colType = 0; tab.colTypeName = "<empty>";
tab.colLength = 0; tab.colScale = 0;
tab.colNullable = 0; tab.binding = NULL;
tab.bytesReturned = 0; tab.colNameLen = 0;
attribs.cRows = attribs.cColumns = 0;
tableInstances++;
};
/* This has no practical use */
int Table::tableInstances = 0;
Table::~Table()
{ tableInstances--; };
void Table::initTable(COLATTRIBUTES a)
{ Schema.push_back(a); };
char * Table::getSchema(int c)
{ return (char *) Schema[c].colName.c_str(); };
void Table::setSchema(COLATTRIBUTES a)
{ Schema.push_back(a); };
RESULTATTR Table::getAttribs()
{ return attribs; };
void Table::setAttribs(int r, int c)
{
attribs.cRows = r;
attribs.cColumns = c;
};
/*
bindColumns is used to assign storage for the results of an SQL statement.
Each table has a set of column attributes which is stored in the Schema
vector. Each column is described by the structure COLATTRIBUTES and one
of the fields of this structure is binding which is a pointer to a piece
of memory allocated to the data for this column.
It also (via SQLBindCol) takes care of conversion of the native data to
chars.
*/
SQLRETURN Table::bindColumns(HSTMT &hstmt)
{ SQLRETURN rc = 0;
int i = 0;
for (i = 0; i < Schema.size(); i++)
{ Schema[i].binding = new char[Schema[i].colLength + 10]; //allocate storage for data
memset(Schema[i].binding, 0, sizeof(Schema[i].binding)); //and zero it
rc = SQLBindCol ( hstmt,
Schema[i].colNum,
SQL_C_CHAR,
Schema[i].binding,
Schema[i].colLength,
&Schema[i].bytesReturned
);
}
return rc;
};
/* buildSchema calls SQLDescribeCol (from the ODBC library) to
determine the relevant information for each attribute of the
result set. The schema is stored in the member Schema which
is a vector of the COLATTRIBUTES structure.
Minimal error checking is done! and this method should probably
be private. It is called with a statement handle reference and
if this points to nowhere in particular - yikes! This would be
a good place to throw an exception or at least use an assertion.
*/
SQLRETURN Table::buildSchema(HSTMT &hstmt, int numCols)
{ int i;
SQLCHAR colName[32];
SWORD colNamelen, colType, scale, nullable;
SQLUINTEGER colLen;
SQLRETURN rc;
COLATTRIBUTES a;
for (i = 0; i < numCols; i++)
{ rc = SQLDescribeCol( hstmt, i + 1, colName, 32, &colNamelen,
&colType, &colLen, &scale, &nullable);
a.colNum = i + 1;
a.colName = (char *) colName;
a.colType = colType;
a.colLength = max(colLen + 4, strlen((char *)colName));
a.colNullable = nullable;
a.colScale = scale;
a.colNameLen = colNamelen;
switch (colType)
{ case SQL_VARCHAR: a.colTypeName = "VARCHAR"; break;
case SQL_CHAR: a.colTypeName = "CHAR"; break;
case SQL_FLOAT: a.colTypeName = "FLOAT"; break;
case SQL_DOUBLE: a.colTypeName = "DOUBLE"; break;
case SQL_NUMERIC: a.colTypeName = "NUMERIC"; break;
case SQL_REAL: a.colTypeName = "REAL"; break;
case SQL_DECIMAL: a.colTypeName = "DECIMAL"; break;
case SQL_INTEGER: a.colTypeName = "INTEGER"; break; //Don't forget to
case SQL_SMALLINT: a.colTypeName = "SMALLINT"; break; //add other data types
default: a.colTypeName = "UNKNOWN"; break;
}
a.bytesReturned = 0;
Schema.push_back(a);
}
};
/* Get the next row from the raw result hstmt and move it to an accessible
storage. It is called with a statement handle reference and uses the
tData member to store the data; tData is a vector of the structure
tableData. At the moment this is just plain text, ie everything, ie the
column data, is converted to text (see bindColumns) above. It might be
better to use the native data type returned by the execution of a
select statement but at the moment this isn't urgent. It should be a
trivial matter to convert data back to some type in the user application.
*/
SQLRETURN Table::transferData(HSTMT & hstmt)
{ SQLRETURN rc = 0;
int i = 0;
while ( (rc = SQLFetch(hstmt)) != SQL_ERROR )
{ if (rc == SQL_SUCCESS || rc == SQL_SUCCESS_WITH_INFO)
{ for (i = 0; i < Schema.size(); i++)
{ rc = SQLGetData( hstmt,
Schema[i].colNum,
SQL_C_CHAR,
Schema[i].binding,
Schema[i].colLength,
&Schema[i].bytesReturned
);
tableData * d;
d = new tableData;
d->text = new char [Schema[i].colLength];
strcpy(d->text, Schema[i].binding);
tData.push_back(*d);
delete d;
}
}
else //Something is wrong
{ return rc;
}
}
return rc;
};
char * Table::getField(int row, int col, int numCols)
{ return tData[(row * numCols) + col].text; };