void PythonOutputDataSet::RetrieveDateTimeColumnFromDataFrame()

in language-extensions/python/src/PythonDataSet.cpp [1333:1407]


void PythonOutputDataSet::RetrieveDateTimeColumnFromDataFrame(
	string      columnName,
	SQLULEN     &columnSize,
	SQLSMALLINT &decimalDigits,
	SQLSMALLINT &nullable)
{
	LOG("PythonOutputDataSet::RetrieveDateTimeColumnFromDataFrame");

	DateTimeStruct *columnData = nullptr;
	SQLINTEGER *strLenOrNullMap = nullptr;
	if (m_rowsNumber > 0)
	{
		columnData = new DateTimeStruct[m_rowsNumber];
		strLenOrNullMap = new SQLINTEGER[m_rowsNumber];
	}

	decimalDigits = 0;
	if constexpr (is_same_v<DateTimeStruct, SQL_TIMESTAMP_STRUCT>)
	{
		// Max datetime2 precision is 7 but python only supports up to microseconds
		// https://docs.microsoft.com/en-us/sql/t-sql/data-types/datetime2-transact-sql
		//
		decimalDigits = 6;
	}

	nullable = SQL_NO_NULLS;
	columnSize = sizeof(DateTimeStruct);
	
	// Get the column as a list of Timestamp objects.
	//
	string script = "list(" + m_name + "['" + columnName + "'])";
	bp::list column = bp::extract<bp::list>(bp::eval(script.c_str(), m_mainNamespace));

	for (SQLULEN row = 0; row < m_rowsNumber; ++row)
	{
		bp::object pyObj = column[row];

		// Make sure the iterator is not pointing at Python None, or else it will crash on extract.
		// Also check the object type for NaT (Not a Time), a special timestamp type,
		// because that should be NULL in SQL as well.
		//
		if (!pyObj.is_none() && 
			strcmp(pyObj.ptr()->ob_type->tp_name, "NaTType") != 0)
		{
			SQL_TIMESTAMP_STRUCT timestamp = ExtractTimestampFromPyObject(pyObj.ptr());
			
			if constexpr (is_same_v<DateTimeStruct, SQL_TIMESTAMP_STRUCT>)
			{
				columnData[row] = timestamp;
			}
			else
			{
				columnData[row] = { timestamp.year, timestamp.month, timestamp.day };
			}
		
			strLenOrNullMap[row] = sizeof(DateTimeStruct);
		}
		else
		{
			strLenOrNullMap[row] = SQL_NULL_DATA;
			nullable = SQL_NULLABLE;
		}
	}

	if (m_rowsNumber > 0)
	{
		m_data.push_back(static_cast<SQLPOINTER>(columnData));
	}
	else
	{
		m_data.push_back(nullptr);
	}

	m_columnNullMap.push_back(strLenOrNullMap);
}