__property Not an allowed type in __published: section

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

__property Not an allowed type in __published: section

Post by theLizard »

I have a component derived from TComponent that I would like to include in the __published section of my header file

__published:
__property TSQLite* SQLite = {read = getSqlite, write = setSqlite};

but I get an E2109 Not an allowed type error, if I move it to the __public section it is fine, however, is there a way to get it to compile without complaint in the __published section as it would be nice to be able to set it at design time with the components dropped on a form.

Cheers
rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

Pointers to TComponent-derived types are perfectly valid for __published properties, so you can link components to each other at design-time. I've written plenty of components with such properties, in both Delphi and C++. The code you have shown looks fine, so I have to think the error is related to the code you have not shown. Can you provide a more complete example? For instance, is TSQLite a complete type before it is used in the __property declaration, or is it just a forward-declaration at that point?
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

rlebeau wrote: Tue Apr 06, 2021 9:44 am Can you provide a more complete example? For instance, is TSQLite a complete type before it is used in the __property declaration, or is it just a forward-declaration at that point?
Thanks Remy,

Not sure what you mean by this "is TSQLite a complete type before it is used in the" but here is the full code of the component I want to use in the __published section of another comonent

Is the TSQLite componentr code all that you want to see or the other as well?

CPP

Code: Select all

 
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TSqliteComponent.h"

#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
//      SQLite info Website's
//      https://www.sqlite.org/quickstart.html
//      https://www.sqlite.org/cintro.html
//			https://www.tutorialspoint.com/sqlite/sqlite_c_cpp.htm
//
//===================================================================================================
TDBRecords* q;
TBaseRecord* r;
char *_ident;
std::vector<TBaseRecord*> rc;
std::vector<TDBRecords*> qr;  //for database table records
std::vector<TDBRecords*> qp;  //for field properties called by pragma
std::vector<TDBRecords*> tn; 	//used to get table names from sqlite_master
int get;
//===================================================================================================
__fastcall TSQLite::~TSQLite()
	{
	}
//---------------------------------------------------------------------------
struct IsColName
	{
	UnicodeString _colName;

	IsColName(UnicodeString colName) : _colName(colName) {}
	bool operator()(const TBaseRecord * item)const
		{
		return(item->c == _colName);
		}
	};
//---------------------------------------------------------------------------
struct IsPropColName
	{
	UnicodeString _propColName;

	IsPropColName(UnicodeString propColName) : _propColName(propColName) {}
	bool operator()(const TBaseRecord * item)const
		{
		return(item->v == _propColName);
		}
	};
//---------------------------------------------------------------------------
struct IsId
	{
	int _id;

	IsId(int id) : _id(id) {}
	bool operator()(const TDBRecords * item)const
		{
		return(item->id == _id);
		}
	};
//---------------------------------------------------------------------------
static int callback(void *NotUsed, int argc, char **argv, char **azColName)
	{
	 int i;
	 for(i = 0; i<argc; i++) {
			printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
	 }
	 printf("\n");
	 return 0;
}
//---------------------------------------------------------------------------
static int selectcallback(void *data, int argc, char **argv, char **azColName)
	{
	//===================================================================================================
	//
	//
	//
	//===================================================================================================

	int i, size = argc;
	q = new TDBRecords();


	if(rc.size() > 0)
		rc.clear();

	q->id = -1;

	for(i = 0; i < size; i++)
		{
		r = new TBaseRecord();

		if(i == 0)
			{
			switch(Load_Which)
				{
				case vTables:
					q->fieldName = "Table";  // was azColName[i];
					q->id = StrToInt(i);
					break;
				case vTableInfo:
				case vRecords:
					q->fieldName = azColName[i];
					q->id = StrToInt(argv[i]);
					break;
				}
			}
		r->c = azColName[i];
		r->v = argv[i] ? argv[i] : "NULL";

		q->br.push_back(r);
		}
		if(q->br.size() > 0)
			{
			switch(get)
				{
				case vTableInfo:
					qp.push_back(q);
					break;
				case vRecords:
					qr.push_back(q);
					break;
				case vTables:
					tn.push_back(q);
				}
			}
	return 0;
	}
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TSQLite *)
	{
	new TSQLite(NULL);
	}
//---------------------------------------------------------------------------
sqlite3 * __fastcall TSQLite::Open(const char *file)
	{
	//===================================================================================================
	// If Database files exists, it will open it
	// If file does not exist, it will create an empty Database file
	//===================================================================================================

	sqlite3_open(file, &_db);

	return _db;
	}
//---------------------------------------------------------------------------
sqlite3 * __fastcall TSQLite::Open16(const char *file)
	{
	sqlite3_open16(file, &_db);
	return _db;
	}
//---------------------------------------------------------------------------
sqlite3 * __fastcall TSQLite::OpenV2(const char *file, int flags,/* Flags */ const char *zVfs)
	{
  // refer https://www.sqlite.org/vfs.html for *zVfs parameter
	sqlite3_open_v2(file, &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, "");
	return _db;

	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Close(sqlite3 *_db)
	{
	sqlite3_close(_db);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::CloseV2(sqlite3 *_db)
	{
	sqlite3_close(_db);
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::Execute( char* sql)
	{
	//===================================================================================================
	//  execute the sql statement a the datbase
	//
	//  DBPath is a property of TSQLite, it must be set before executing any sql statement
	//      SQLite1->DBPath = drive\\path\\anydatabase.db
	//===================================================================================================
	zErrMsg = 0;
	UnicodeString s="";

	/* Execute SQL statement */
	 rc = sqlite3_exec((_db = Open(UnicodeToChar(DBPath))), sql, callback, 0, &zErrMsg);
	 if(rc != SQLITE_OK)
		{
		s = CharToUnicode(zErrMsg);
		Application->MessageBoxW(s.w_str(), L"Error", IDOK );
		sqlite3_free(zErrMsg);
		}

	if(_db)
		Close(_db);

	return(rc);
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::Execute(UnicodeString sql)
	{
	//===================================================================================================
	//  execute the sql statement a the datbase
	//
	//  DBPath is a property of TSQLite, it must be set before executing any sql statement
	//      SQLite1->DBPath = drive\\path\\anydatabase.db
	//===================================================================================================
	zErrMsg = 0;
	UnicodeString s="";
	int rc;

	rc = sqlite3_exec((_db = Open(UnicodeToChar(DBPath))), UnicodeToChar(sql), callback, 0, &zErrMsg);

	if(rc != SQLITE_OK)
		{
		s = CharToUnicode(zErrMsg);
		Application->MessageBoxW(s.w_str(), L"Error", IDOK );
		sqlite3_free(zErrMsg);
		}

	if(_db)
		Close(_db);

	return(rc);
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
	{
	//===================================================================================================
	//  this function, via callback, fills a vector of 	std::vector<TDBRecords*> qr
	//                                                  has properties of TDBRecords;
	//                                                      UnicodeString 	fieldName
	//                                                      int 						id
	//	which contains a vector of 											std::vector<TBaseRecord*> rc
	//                                                  has properties of TBaseRecord;
	//                                                      UnicodeString   c, v, t, l
	//  callback function fills vector of returned records from database
	//  the vector contains colum name, column value and column type
	//  q->records[0]->c
	//  q->records[0]->v
	//===================================================================================================
	UnicodeString s;
	int size;
	data = "Callback function called by SelectSql";
	qr.clear();

	q = new TDBRecords();


	get = _get;
	_ident = _id;

	if(_id == "")
		_id= "";

	rc = sqlite3_exec((_db = Open(UnicodeToChar(DBPath))),  UnicodeToChar(sql), selectcallback, (void*)data, &zErrMsg);

	switch(get)
		{
		case  vRecords:
		case  vTableInfo:
			size = (int)qr.size();
			break;
		case vTables:
			size = (int)tn.size();
			break;
		}
	if(size > 0)
		{
		switch(get)
			{
			case vRecords:
				dbQueryResult.clear();
				for(int i = 0; i < qr.size(); i++)
					dbQueryResult.push_back(qr[i]);
				break;
			case vTableInfo:
				dbPropertyResult.clear();
				for(int i = 0; i < qr.size(); i++)
					dbPropertyResult.push_back(qr[i]);
				break;
			case vTables:
				dbTablesResult.clear();
				for(int i = 0; i < tn.size(); i++)
					dbTablesResult.push_back(tn[i]);
				break;

			}
		}

	if(rc != SQLITE_OK)
		{
		s = CharToUnicode(zErrMsg);
		Application->MessageBoxW(s.w_str(), L"Error", IDOK );
		sqlite3_free(zErrMsg);
		}

	if(_db)
		Close(_db);

	return(rc);
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)
	{
	//===================================================================================================
	//  this function, via callback, fills a vector of 	std::vector<TDBRecords*> qr
	//                                                  has properties of TDBRecords;
	//                                                      UnicodeString 	fieldName
	//                                                      int 						id
	//	which contains a vector of 											std::vector<TBaseRecord*> rc
	//                                                  has properties of TBaseRecord;
	//                                                      UnicodeString   c, v, t, l
	//  callback function fills vector of returned records from database
	//  the vector contains colum name, column value and column type
	//  q->records[0]->c
	//  q->records[0]->v
	//===================================================================================================
	UnicodeString s;
	data = "Callback function called by SelectSql";
	qr.clear();
	qp.clear();
	q = new TDBRecords();

	get = _get;

	rc = sqlite3_exec((_db = Open(UnicodeToChar(DBPath))),  UnicodeToChar(sql), selectcallback, (void*)data, &zErrMsg);

	if((int)qr.size() > 0)
		{
		switch(get)
			{
			case vRecords:
				dbQueryResult.clear();
				for(int i = 0; i < qr.size(); i++)
					dbQueryResult.push_back(qr[i]);
				break;
			case vTableInfo:
				dbPropertyResult.clear();
				for(int i = 0; i < qr.size(); i++)
					dbPropertyResult.push_back(qr[i]);
				break;
			}
		}

	if(rc != SQLITE_OK)
		{
		s = CharToUnicode(zErrMsg);
		Application->MessageBoxW(s.w_str(), L"Error", IDOK );
		sqlite3_free(zErrMsg);
		}

	if(_db)
		Close(_db);

	return(rc);
	}
//---------------------------------------------------------------------------
std::vector<TBaseRecord*>& __fastcall TSQLite::GetValuesByrecordId(int id)
	{
	//===================================================================================================
	// this function finds and returns, if it exists, the vector of TBaseRecords in the TDBRecords vector.
	// TDBRecord has 2 properties, fieldName and id
	//    the vector, [std::vector<TBaseRecord*> br;] stores the column data of the record set
	//    returned by a SELECT statement
	//
	// example call to this function;
	//	 br = sq->GetValuesByrecordId(5); get the vector of record values
	//	 sz = br[18]->v;  extract the field value of interest from the record by the index of the field element
	//===================================================================================================
	int index = -1;

	std::vector<TDBRecords*>::iterator found = std::find_if(dbQueryResult.begin(), dbQueryResult.end(), IsId(id));

	if(found != dbQueryResult.end())
		index = std::distance(dbQueryResult.begin(), found);

	return(dbQueryResult[index]->br);
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::GetValuesByrecordId(int id, UnicodeString col_name)
	{
	//===================================================================================================
	// this function finds the field value of the column name being queried by it's record id
	// example call to this function;
	//      sz = SQLite1->GetValuesByrecordId(6, "pfactor");
	//===================================================================================================
	UnicodeString v;
	int found;

	v = GetFieldValue(GetValuesByrecordId(id), col_name, found);

	return(v);
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::GetFieldValue(std::vector<TBaseRecord*>& r, UnicodeString col_name, int &_foundIndex)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i]->br, _colName, found)
	//        UnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0]->br, "pfactor", found);
	//===================================================================================================
	int index = -1;

	if(r.size() == 0)
		return("Nothing found");

	std::vector<TBaseRecord*>::iterator found = std::find_if(r.begin(), r.end(), IsColName(col_name));

	if(found != r.end())
		_foundIndex = index = std::distance(r.begin(), found);

	return(r[index]->v);
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetPropFieldValue(std::vector<TBaseRecord*>& r, UnicodeString col_name)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i]->br, _colName, found)
	//        UnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0]->br, "pfactor", found);
	//===================================================================================================
	int index = -1;

	std::vector<TBaseRecord*>::iterator found = std::find_if(r.begin(), r.end(), IsPropColName(col_name));

	if(found != r.end())
		index = std::distance(r.begin(), found);


	return(index);
	}
//---------------------------------------------------------------------------
char * __fastcall TSQLite::UnicodeToChar(UnicodeString s)
	{
	AnsiString ansiB(s);
	str = new char[ansiB.Length()+1];
	strcpy(str, ansiB.c_str());

	return(str);
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::CharToUnicode(char* str)
	{
	UnicodeString s;
	AnsiString a = a.sprintf(str);

	return((s=a));
	}
// ---------------------------------------------------------------------
void __fastcall TSQLite::TableInfo(UnicodeString table)
	{
	//===================================================================================================
	//	SQLite request:  "pragma table_info(" + table + ")" to fill std::vector<TDBRecords*> qp
	//          -------------------------------------------------
	//					cid,	name,	type,				notnull,	dflt_value,	pk
	//          -------------------------------------------------
	//					0,		id,		INTEGER,		0,				NULL,				1
	//
	// 	example of call to this function;
	//        SQLite1->TableInfo("Readings");
	//
	// 	qr = vector of records collection containing vector of returned record values
	// 	qp = vector of all field properties based on column name from table queried to abtain values of records in qr vector
	//    get column name  _colName
	//    interate through qr and get each vector of record
	//		if(qr[0]->br[i]->c == _colName) //match found
	//      {
	//      qr[0]->br[i]->v = qp[0]->br[2]->v;
	//			}
	//	qp[0]->br[1]->v = u"id"
	//	qp[0]->br[2]->v = u"INT[4]"
	//	qp[1]->br[1]->v = u"make"
	//	qp[1]->br[2]->v = u"VARCHAR"
	//	qp[2]->br[1]->v = u"year"
	//	qp[2]->br[2]->v = u"VARCHAR"
	//===================================================================================================
	UnicodeString	 sql = "pragma table_info(" + table + ")";
	UnicodeString p, _colName;
	int size, count, x, c, found=-1;
	Load_Which = vTableInfo;
	_tableName = table;
	qp.clear();

	if((rc=SelectSql(sql, "cid", vTableInfo)) != SQLITE_OK)
		return;

	TBaseRecord* r;

	for(x = 0; x < (c = qp.size()); x++)  // loop by the vulue of the number of TBaseRecords in property type vector qp
		{
		_colName = qp[x]->br[1]->v;  								//assign column name to var
		found = -1;                  								//reset found var to -1, not found
		r = qp[x]->br[1];            								//extract the base record from vector
		found = GetPropFieldValue(qp[x]->br, _colName);	//find the index of the col def vector record containg the type
		r->t = qp[x]->br[found+1]->v;                 //assign the field type to the base record field type for later use.
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::GetDatabaseTables()
	{
	UnicodeString p, _colName;
	int size, count, x, c, found=-1;
	Load_Which = vTables;
	tn.clear();

	if((rc=SelectSql(SQLITE_TABLE, "cid", vTables)) != SQLITE_OK)
		return;

	TBaseRecord* r;

	for(x = 0; x < (c = tn.size()); x++)  						//loop by the vulue of the number of TBaseRecords in property type vector qp
		{
		_colName = tn[x]->br[1]->v;  										//assign column name to var
		found = -1;                  										//reset found var to -1, not found
		r = tn[x]->br[1];            										//extract the base record from vector
		found = GetPropFieldValue(tn[x]->br, _colName);	//find the index of the col def vector record containg the type
		r->t = tn[x]->br[found+1]->v;                 	//assign the field type to the base record field type for later use.
		}
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::PropertyType(std::vector<TBaseRecord*>& r, UnicodeString name)
	{
	//===============================================================================================
	// get the property type from vector of field values
	// example of call to this function;
	// 				sz = SQLite1->PropertyType(SQLite1->dbQueryResult[1]->br, "pfactor");
	//===============================================================================================
	int i, found=-1;
	UnicodeString sz;

	GetFieldValue(r, name, found);	//find the index into the vector containg the type value of the column name

	sz = r[found]->t;
	return(sz);
	 }
//---------------------------------------------------------------------------
void __fastcall TSQLite::FillComboBox(TSQLiteComboBox *c, UnicodeString sql, UnicodeString field)
	{
	//===============================================================================================
	//  This function fills a TSQLiteComboBox *c with values defined by the field parameter in the call.
	//
	//  sql contains the sql select statement to be executed
	//  field is the databse column name in the returned data set
	//
	// example of call to this function;
	//    SQLite1->FillComboBox(cb_Location , sql, "column_name");
	//
	//===============================================================================================
	int i;
	c->Clear();
	//===============================================================================================
	// 	recordsId is a vector of database record id's matched to the combo items strings
	//  this allows for retrieval of db record by it's record id from a combo box item.
	//  the RecordId property is set when the item in the combo box is selected
	//
	// 	example usage fro call to SQLite DB;
	//    sql = "SELECT * FROM table WHERE reordid = " + IntToStr(c->RecordId);
  //    SelectSql(sql, vRecords);
	//===============================================================================================
	c->recordIds.clear();
	SelectSql(sql, vRecords);
	if(qr.size() > 0)
		{

		for(i = 0; i < (int)qr.size(); i++)
			{
			c->recordIds.push_back(qr[i]->id);
			c->Items->Add( GetValuesByrecordId(qr[i]->id, field));
			}
		}
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords*>& __fastcall TSQLite::FieldProps()
	{
	return(dbPropertyResult);
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords*>& __fastcall TSQLite::FieldValues()
	{
	return(dbQueryResult);
	}
//---------------------------------------------------------------------------
__fastcall TBaseRecord::TBaseRecord(){}
//---------------------------------------------------------------------------
__fastcall TDBRecords::TDBRecords(){}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::getDatabaseSource()
	{
	return(_dbSource);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::setDatabaseSource(UnicodeString value)
	{
	if(_dbSource != value)
		_dbSource = value;
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::AddParameter(UnicodeString ColumnName, UnicodeString Value)
	{
	//
	UnicodeString sz, type;
	int index;
	bool found = false;

	if(qp.size() == 0)
		{
		sz = "Field types have not yet been obtained for parameter bindings..";
		Application->MessageBoxW(sz.w_str(), L"Add Parameter Fail", MB_OK);
		return(false);
		}

	param = new TSQLiteParameters();
	param->ColumnName = ColumnName;
	param->ParamName = "p" + IntToStr((int)Params.size());
	param->ParamValue = Value;

	if(FindType(ColumnName, type ))
		param->ColumnType = type; //get the column type from the qp vector using column name

	Params.push_back(param);

	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindType(UnicodeString ColumnName, UnicodeString &value)
	{
	int size, count, x, c, found;
	UnicodeString _colName;

	TBaseRecord* r;
	for(x = 0; x < (c = qp.size()); x++)  // 	loop by the vulue of the number of TBaseRecords in property type vector qp
		{
		_colName = qp[x]->br[1]->v;    			//	assign column name to var

		if(_colName != ColumnName)          //  compare vector element with ColumnName parameter
			continue;                         //  vector element not the same, continue on...

		r = qp[x]->br[1];            										//extract the base record vector from vector of TBaseRecords
		found = GetPropFieldValue(qp[x]->br, _colName);	//find the index of the col def vector record containg the type
		value = qp[x]->br[found+1]->v;                 	//assign the field type to the base record field type for later use.
		}

	if(value.IsEmpty())
		return(false);

	return(true);

	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value)
	{
  return(FindPropertyValue(ColumnName, value));
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value, int _property)
	{
	int size, count, x, c, found;
	UnicodeString _colName;

	TBaseRecord* r;
	for(x = 0; x < (c = qp.size()); x++)  // 	loop by the vulue of the number of TBaseRecords in property type vector qp
		{
		_colName = qp[x]->br[1]->v;    			//	assign column name to var

		if(_colName != ColumnName)          //  compare vector element with ColumnName parameter
			continue;                         //  vector element not the same, continue on...

		r = qp[x]->br[1];            										//extract the base record vector from vector of TBaseRecords
		found = GetPropFieldValue(qp[x]->br, _colName);	//find the index of the col def vector record containg the type
		switch(_property)
			{
			case pColtype:
				value = qp[x]->br[found+1]->v;                 	//assign the field type to the base record field type for later use.
				break;
			case pNotNull:
				value = qp[x]->br[found+2]->v;                 	//assign the field type to the base record field type for later use.
				break;
			case pDflt_Value:
				value = qp[x]->br[found+3]->v;                 	//assign the field type to the base record field type for later use.
				break;
			case pPk:
				value = qp[x]->br[found+4]->v;                 	//assign the field type to the base record field type for later use.
				break;
			}
		}

	if(value.IsEmpty())
		return(false);

	return(true);

	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::ClearParameters()
	{
	if(Params.size() > 0)
		Params.clear();
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::Prepair(sqlite3 *_db, UnicodeString s)
	{
	char *str;
	sqlite3_stmt *stmt;
	double value;
	str = UnicodeToChar(s);
	ops = new TSQLiteOperations();

	rc = sqlite3_prepare_v2(_db, str, -1, &stmt, 0);

	if(rc != SQLITE_OK)
		{
		printf("SQL error on line:%d msg:%s \n",__LINE__, sqlite3_errmsg(_db));
		}


	//==========================================================================
	//  sqlite bind columns
	//
	//  bind colums based on column data type - use TableInfo( table name)
	//  to get data types for the bind process
	//
	//  possible method:   enum bindtype {tInt, ...};
	//										 Bind(int type, sqlite3_stmt *stmt, int valueCount, int value)
	//    rc = sqlite3_bind_int( tInt, stmt, vgalueCount, value);
	//    Bind(tInt, stmt, valueCount, 2015);
	//    switch(type)
	//      {
	//      case tInt:
	// 				rc = sqlite3_bind_int(stmnt, 1, 2015);
	//      }
	//==========================================================================
 //	rc = sqlite3_bind_int(  test1, 1, 2015);
	//	rc = sqlite3_bind_int(  test1, 2, stat_time.tv_sec);

	rc = ops->Bind(tText, stmt, 1, "NH46034");

	do
		{
		rc = sqlite3_step( stmt);

		switch( rc )
			{
			 /**  SQLITE_DONE  101 -- sqlite3_step() has finished executing  */
			 case SQLITE_DONE:
					break;

			 /** New data */
			 case SQLITE_ROW:
				 {
						uint16_t size = sqlite3_column_count( stmt);

						if(size == 1) // should always be one
						{
							 value   = sqlite3_column_double( stmt, 0);
							 printf("test 1 = %f %s\n",value, sqlite3_column_text(stmt, 0));
						}
				 }
			 break;

			 default:
					break;
			}
		}
	while( rc==SQLITE_ROW );


	return(rc);
	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowProptiesInTreeView()
	{
	int i, j;
	UnicodeString s = "Column ";
	TSQLiteTreeNode *root, *child, *sibling;
	TreeView->ClearNodes();
	root = TreeView->AddRoot(TreeView->o, "Table Name: " + _tableName);
	for(i = 0; i < qp.size(); i++)
		{
		for(j = 0; j < qp[i]->br.size(); j++)
			{
			if(j == 0)
				child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + qp[i]->br[j]->v);
			else
				sibling = TreeView->AddTreeNode(child, TreeView->o, s + qp[i]->br[j]->c + " : " + qp[i]->br[j]->v);
			}
		}
	return(dynamic_cast<TTreeNode*>(root));
	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowQueryResultsInTreeView()
	{
	int i, j;
	TSQLiteTreeNode *root, *child, *sibling;
	TreeView->ClearNodes();
	root = TreeView->AddRoot(TreeView->o, "Query Result");
	for(i = 0; i < qr.size(); i++)
		{
		for(j = 0; j < qr[i]->br.size(); j++)
			{
			if(j == 0)
				child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + qr[i]->br[j]->v);
			else
				sibling = TreeView->AddTreeNode(child, TreeView->o, qr[i]->br[j]->c + " : " + qr[i]->br[j]->v);
			}
		}
	return(dynamic_cast<TTreeNode*>(root));

	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowSQLiteMasterQueryResultsInTreeView()
	{
	int i, j;
	TSQLiteTreeNode *root, *child, *sibling;
	TreeView->ClearNodes();
	root = TreeView->AddRoot(TreeView->o, "Query Result");
	for(i = 0; i < tn.size(); i++)
		{
		for(j = 0; j < tn[i]->br.size(); j++)
			{
			if(j == 0)
				child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + tn[i]->br[j]->v);
			else
				sibling = TreeView->AddTreeNode(child, TreeView->o, tn[i]->br[j]->c + " : " + tn[i]->br[j]->v);
			}
		}
	return(dynamic_cast<TTreeNode*>(root));

	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetLastAutoIncrement(UnicodeString table)
	{
	//  Get the last sequence AUTOINCREMENT number of a table for AUTOINCREMENT field if any.
	UnicodeString sql = "select seq from sqlite_sequence where name = '" + table + "'";
	int sequence = -1;

	if(SelectSql(sql, vRecords) == SQLITE_OK)
		if(qr.size() > 0){sequence = StrToInt(qr[0]->br[0]->v);}
	return(sequence);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::setTv(TSQLiteTreeView* tv)
	{
	if(_tv != tv)
		_tv = tv;
	}
//---------------------------------------------------------------------------
TSQLiteTreeView* __fastcall TSQLite::getTv()
	{
	return(_tv);
	}
//---------------------------------------------------------------------------
__fastcall TSQLite::TSQLite(TComponent* Owner)
	: TComponent(Owner)
		{
		}
//---------------------------------------------------------------------------
namespace Tsqlitecomponent
{
	void __fastcall PACKAGE Register()
	{
		TComponentClass classes[1] = {__classid(TSQLite)};
		RegisterComponents(L"SQLite", classes, 0);
	}
}
//---------------------------------------------------------------------------
 
Header -- .H

Code: Select all

//---------------------------------------------------------------------------

#ifndef TSqliteComponentH
#define TSqliteComponentH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <windows.h>
#include <StrUtils.hpp>

#include <vector>
#include <algorithm>

#include "sqlite3.h"
//#include "sqlite3ext.h"
#include "TSQLiteOperations.h"
#include "TSQLiteParameters.h"
#include "TSQLiteTreeView.h"
#include "TSQLiteAgent.h"

#include "TSQLiteComboBox.h"
enum loadwhich {vRecords, vTableInfo, vTables};
enum pProperty {pColtype, pNotNull, pDflt_Value, pPk};

#define SQLITE_TABLE "SELECT * FROM sqlite_master ORDER BY type"
int Load_Which;
//---------------------------------------------------------------------------
class PACKAGE TSQLite : public TComponent
	{
	friend class TBaseRecord;
	friend class TDBRecords;
	friend class TSQLiteComboBox;
	friend class TSQLiteTreeView;
  friend class TSQLiteAgent;
	private:
		sqlite3 *_db;
		char* str;
		char *zErrMsg;
		int rc;

		const char* data;
		TBaseRecord *r;
		UnicodeString _ident;
		UnicodeString _dbSource;
		TSQLiteParameters *param;
		std::vector<TDBRecords*> dbQueryResult;
		std::vector<TDBRecords*> dbPropertyResult;
		std::vector<TDBRecords*> dbTablesResult;
		UnicodeString __fastcall getDatabaseSource();
		void __fastcall setDatabaseSource(UnicodeString value);
		TSQLiteTreeView* _tv;
		UnicodeString _tableName;

		void __fastcall setTv(TSQLiteTreeView* tv);
		TSQLiteTreeView* __fastcall getTv();

	protected:
		TSQLiteOperations* ops;
	public:
		__fastcall TSQLite(TComponent* Owner);
		__fastcall ~TSQLite();
		TTreeNode* __fastcall ShowProptiesInTreeView();
		TTreeNode* __fastcall ShowQueryResultsInTreeView();
		TTreeNode* __fastcall ShowSQLiteMasterQueryResultsInTreeView();
		int __fastcall GetLastAutoIncrement(UnicodeString table);

		std::vector<TBaseRecord*>& __fastcall GetValuesByrecordId(int id);
		std::vector<TDBRecords*>& __fastcall FieldProps();
		std::vector<TDBRecords*>& __fastcall FieldValues();
		std::vector<TSQLiteParameters*> Params;

		char * __fastcall UnicodeToChar(UnicodeString s);
		sqlite3 * __fastcall Open(const char *file);
		sqlite3 * __fastcall Open16(const char *file);
		sqlite3 * __fastcall OpenV2(const char *file, int flags,/* Flags */ const char *zVfs);
		void __fastcall Close(sqlite3 *_db);
		void __fastcall CloseV2(sqlite3 *_db);
		void __fastcall TableInfo(UnicodeString table);
		int __fastcall SelectSql(UnicodeString sql, UnicodeString _id, int _get);
		int __fastcall SelectSql(UnicodeString sql, int _get);
		int __fastcall Execute(char* sql);
		int __fastcall Execute(UnicodeString sql);
		UnicodeString __fastcall PropertyType(std::vector<TBaseRecord*>& r, UnicodeString name);
		UnicodeString __fastcall GetFieldValue(std::vector<TBaseRecord*>& r, UnicodeString col_name, int &_foundIndex);
		int __fastcall GetPropFieldValue(std::vector<TBaseRecord*>& r, UnicodeString col_name);
		UnicodeString __fastcall ValueType(UnicodeString colName, std::vector<TBaseRecord*>& r);
		UnicodeString __fastcall GetValuesByrecordId(int id, UnicodeString col_name);
		UnicodeString __fastcall CharToUnicode(char* str);
		void __fastcall FillComboBox(TSQLiteComboBox* c,UnicodeString sql, UnicodeString field);
		int __fastcall Prepair(sqlite3 *_db, UnicodeString s);
		bool __fastcall AddParameter(UnicodeString ColumnName, UnicodeString Value);
		bool __fastcall FindType(UnicodeString _column_name, UnicodeString &value);
    bool __fastcall FindPropertyValue(UnicodeString ColumnName, UnicodeString &value, int _property);
    bool __fastcall FindPropertyValue(UnicodeString ColumnName, UnicodeString &value);
		void __fastcall ClearParameters();
    void __fastcall GetDatabaseTables();

	__published:
		__property UnicodeString DBPath = {read=getDatabaseSource, write=setDatabaseSource};
		__property TSQLiteTreeView* __fastcall TreeView = {read = getTv, write = setTv};
	};
//---------------------------------------------------------------------------
class TBaseRecord
	{
	//===================================================================================================
	// storage for each column returned by an select a statement
	// example:
	//		sql = "SELECT * FROM MAKE";  gets all columns from table make.
	//===================================================================================================
	friend class TSQLite;
	friend class TDBRecords;
	private:

	public:
		UnicodeString c; // column name
		UnicodeString v; // value
		UnicodeString t; // column type
		UnicodeString l; // column length

		__fastcall TBaseRecord();
	};
//---------------------------------------------------------------------------
class TDBRecords
	{
	//===================================================================================================
	// vector of all record values returned from database sql query
	//
	//===================================================================================================
	friend class TSQLite;
	friend class TBaseRecord;
	private:

	public:
		UnicodeString fieldName; 	// column name
		int id;

		__fastcall TDBRecords();
		std::vector<TBaseRecord*> br;

	};
//---------------------------------------------------------------------------
#endif


rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

theLizard wrote: Tue Apr 06, 2021 3:19 pm Not sure what you mean by this "is TSQLite a complete type before it is used in the"
Do you know what a forward-declaration is? And the difference between a complete class type vs a forward-declared class type?

OK, let me put it to you this way - preceding the offending __property declaration, does the other component have an "#include TSqliteComponent.h" statement, or does it have a "class TSQLite;" statement? IOW, has the compiler actually seen the complete TSQLite class, or only knows that TSQLite exists but not what it looks like yet?
theLizard wrote: Tue Apr 06, 2021 3:19 pm but here is the full code of the component I want to use in the __published section of another comonent
Didn't need that CPP file, especially since 99.999999% of it doesn't apply to this issue at all.

But since you did provide the CPP file, I see A LOT of problems with it - memory leaks, lack of proper exception handling (and apparently an unwillingness to throw exceptions where they are warranted), logic errors, etc. And that was just from a cursory glance, there is just way too much code to go through in detail.

One __property related issue I do want to point out:

Code: Select all

__property TSQLiteTreeView* __fastcall TreeView = {read = getTv, write = setTv};
__fastcall does not belong in a __property declaration, so get rid of that:

Code: Select all

__property TSQLiteTreeView* TreeView = {read = getTv, write = setTv};
theLizard wrote: Tue Apr 06, 2021 3:19 pm Is the TSQLite componentr code all that you want to see or the other as well?
I would need to see the other component (at least the H file for it) that has the __property declaration that is failing to compile.
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

rlebeau wrote: Tue Apr 06, 2021 5:31 pm does the other component have an "#include TSqliteComponent.h" statement
Yes..
rlebeau wrote: Tue Apr 06, 2021 5:31 pm But since you did provide the CPP file, I see A LOT of problems with it
Yep, lot's of work still to be done in this regard
rlebeau wrote: Tue Apr 06, 2021 5:31 pm memory leaks, lack of proper exception handling (and apparently an unwillingness to throw exceptions where they are warranted), logic errors, etc. And that was just from a cursory glance
This is work in progress and am a bit lazy and impatient to see something work from some of my ideas, I always go back and put in and try to find the issues you have stated.

ATM, the component does what it is supposed to do with all it's imperfections, as time goes by, it will be optimized with all error handling implemented.
rlebeau wrote: Tue Apr 06, 2021 5:31 pm __fastcall does not belong in a __property declaration, so get rid of that:
My bad on this one, I do not do that normally, not even sure why I put that there in the first place, old timers disease I think.

The following is th .h file for the other component, it is a component being modified to work with the sqlite3 interface and just started working on it yesterday.


Code: Select all

#ifndef TSQLiteAgentH
#define TSQLiteAgentH
// ---------------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
// ---------------------------------------------------------------------------------
#include <ComCtrls.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <ExtCtrls.hpp>
#include <algorithm>
#include <Forms.hpp>
#include <Buttons.hpp>
#include "SqlTimSt.hpp"
#include <TypInfo.hpp>
#include "TSQLiteEdit.h"
#include "TSQLiteComboBox.h"
#include "TSQLiteCheckListBox.h"
#include "TSQLiteFieldsFilter.h"
#include "TSQLiteFieldProp.h"
#include "TSQLiteFormsAgent.h"

#include "TSQLiteDateTimePicker.h"
#include "TSQLiteMemo.h"
#include "TSQLiteCheckBox.h"
#include "TSQLiteHintPanel.h"
#include "TSQLiteIncludes.h"
#include "TSQLiteListBox.h"
#include "TSQLiteParameters.h"
#include <Graphics.hpp>
#include <jpeg.hpp>
#include <pngimage.hpp>
#include "TSqliteComponent.h"


// ---------------------------------------------------------------------------------
class PACKAGE TSQLiteAgent : public TComponent
	{
	typedef void __fastcall (__closure *TSQLiteAgentGetColDefs)(System::TObject *Sender, bool Loaded);
	typedef void __fastcall (__closure *TSQLiteAgentFieldFocusedEvent)(System::TObject *Sender, TControl* Ctrl);
	typedef void __fastcall (__closure *TSQLiteAgentSetRecordEvent)(bool Done, System::TObject *Sender);
	typedef void __fastcall (__closure *TSQLiteAgentSetValueErrorEvent)(System::TObject *Sender, UnicodeString Message, bool done);

	friend class TSQLiteFormsAgent;
//	friend class TLOdbcCon;
	friend class TSQLiteComboBox;
	friend class TSQLiteCheckListBox;
	friend class TSQLiteCheckBox;
	friend class TSQLiteDateTimePicker;
	friend class TSQLiteMemo;
	friend class TSQLiteEdit;
	friend class TSQLiteParameters;
	friend class TSQLite;

	private:
		TForm* Fowner;
		//TNotifyAction* Finform;
		//TNotifyAction* Faction;
		TCustomButton* Fadd;
		TCustomButton* Fedit;
		TCustomButton* Fsave;
		TCustomButton* Fdel;
		TCustomButton* Fcancel;
		TCustomButton* Fexit;
		TSQLiteAgent* Flinktoagent;
		TObject* Fobject;
		TSQLiteFormsAgent* FformsAgent;
		TTreeNode* FparentNode;
		TTreeNode* FselectedNode;
		TTreeNode* FToExpand;
//		TLOdbcCon* FcurDb;
		TWinControl* FcurP;
		UnicodeString FcurSql;
		TSQLiteHintPanel* FhintPanel;
		TColor FhintBg;
		TColor FhintFg;
		UnicodeString Ffloatformat;
		UnicodeString FselectSql;
		UnicodeString FinsertSql;
		UnicodeString FloadSql;
		UnicodeString FdeleteSql;
		UnicodeString FupdateSql;
		UnicodeString Ftitle;
		UnicodeString FexpandNode;
		UnicodeString FclassName;
		UnicodeString Fdata;
		UnicodeString Fgroup;
		bool FformCreated;
		bool FcaptionIsTitle;
		bool FrecordSaved;
		bool FnewRecord;
		bool Fclosing;
		bool FshowHints;
		int FformIndex;
		int FrecordId;
		int FfieldCount;
		int FLastfieldorder;
		int FLast;
		int FBiggest;
		int FSmallest;;
		int FparentNodeId;;
		bool FenableHints;

		bool __fastcall getEnableHints();
		void __fastcall  setEnableHints(bool value );
		TSQLite *_sqlite;
		TSQLite * __fastcall getSqlite();
		void __fastcall setSqlite(TSQLite *value);

		TForm* __fastcall getOwner();
		void __fastcall setOwner(TForm* value );
//		TNotifyAction* __fastcall getInform();
//		void __fastcall setInform(TNotifyAction* value );
//		TNotifyAction* __fastcall getAction();
//		void __fastcall setAction(TNotifyAction* value );
		TCustomButton* __fastcall getAdd();
		void __fastcall setAdd(TCustomButton* value );
		TCustomButton* __fastcall getEdit();
		void __fastcall setEdit(TCustomButton* value );
		TCustomButton* __fastcall getSave();
		void __fastcall setSave(TCustomButton* value );
		TCustomButton* __fastcall getDel();
		void __fastcall setDel(TCustomButton* value );
		TCustomButton* __fastcall getCancel();
		void __fastcall setCancel(TCustomButton* value );
		TCustomButton* __fastcall getExit();
		void __fastcall setExit(TCustomButton* value );
		TSQLiteAgent* __fastcall getLinktoagent();
		void __fastcall setLinktoagent(TSQLiteAgent* value );
		TObject* __fastcall getObject();
		void __fastcall setObject(TObject* value );
		TSQLiteFormsAgent* __fastcall getFormsAgent();
		void __fastcall setFormsAgent(TSQLiteFormsAgent* value );
		TTreeNode* __fastcall getParentNode();
		void __fastcall setParentNode(TTreeNode* value );
		TTreeNode* __fastcall getSelectedNode();
		void __fastcall setSelectedNode(TTreeNode* value );
		TTreeNode * __fastcall getNodeToExpand();
		void __fastcall  setNodeToExpand(TTreeNode *value);
//		TLOdbcCon* __fastcall getCurDb();
//		void __fastcall setCurDb(TLOdbcCon* value );
		TWinControl* __fastcall getCurP();
		void __fastcall setCurP(TWinControl* value );
		UnicodeString __fastcall getCurSql();
		void __fastcall setCurSql(UnicodeString value );
		TSQLiteHintPanel* __fastcall getHintPanel();
		void __fastcall setHintPanel(TSQLiteHintPanel* value );
		TColor __fastcall getHintBg();
		void __fastcall setHintBg(TColor value );
		TColor __fastcall getHintFg();
		void __fastcall setHintFg(TColor value );
		UnicodeString __fastcall getFloatformat();
		void __fastcall setFloatformat(UnicodeString value );
		UnicodeString __fastcall getSqlSelect();
		void __fastcall setSqlSelect(UnicodeString value);
		UnicodeString __fastcall getSqlInsert();
		void __fastcall setSqlInsert(UnicodeString value);
		UnicodeString __fastcall getSqlLoad();
		void __fastcall setSqlLoad(UnicodeString value);
		UnicodeString __fastcall getSqlUpdate();
		void __fastcall setSqlUpdate(UnicodeString value);
		UnicodeString __fastcall getSqlDelete();
		void __fastcall setSqlDelete(UnicodeString value);
		UnicodeString __fastcall getTitle();
		void __fastcall setTitle(UnicodeString value );
		UnicodeString __fastcall getExpandNode();
		void __fastcall setExpandNode(UnicodeString value );
		UnicodeString __fastcall getClassName();
		void __fastcall setClassName(UnicodeString value );
		UnicodeString __fastcall getData();
		void __fastcall setData(UnicodeString value );
		UnicodeString __fastcall getGroup();
		void __fastcall setGroup(UnicodeString value );
		bool __fastcall getFormCreated();
		void __fastcall setFormCreated(bool value );
		bool __fastcall getCaptionIsTitle();
		void __fastcall setCaptionIsTitle(bool value );
		bool __fastcall getRecordSaved();
		void __fastcall setRecordSaved(bool value );
		bool __fastcall getNewRecord();
		void __fastcall setNewRecord(bool value );
		bool __fastcall getClosing();
		void __fastcall setClosing(bool value );
		bool __fastcall getShowHints();
		void __fastcall setShowHints(bool value );
		int __fastcall getRecordId();
		void __fastcall setRecordId(int value );
		int __fastcall getFieldCount();
		void __fastcall setFieldCount(int value );
		int __fastcall getLastfieldorder();
		void __fastcall setLastfieldorder(int value );
		int __fastcall getLast();
		void __fastcall setLast(int value );
		int __fastcall getBiggest();
		void __fastcall setBiggest(int value );
		int __fastcall getSmallest();
		void __fastcall setSmallest(int value );
		int __fastcall getParentNodeId();
		void __fastcall setParentNodeId(int value );

		TColor __fastcall getLabelEnabled();
		void __fastcall setLabelEnabled(TColor value);
		TColor __fastcall getLabelDisabled();
		void __fastcall setLabelDisabled(TColor value);

		TColor __fastcall getFieldEnabled();
		void __fastcall setFieldEnabled(TColor value);
		TColor __fastcall getFieldDisabled();
		void __fastcall setFieldDisabled(TColor value);
		UnicodeString __fastcall getFloatFormat();
		void __fastcall setFloatFormat(UnicodeString value);
		TColor __fastcall getHintBackgroundColor();
		void __fastcall setHintBackgroundColor(TColor value);
		TColor __fastcall getHintForeGroundColor();
    		void __fastcall setHintForeGroundColor(TColor value);

		int __fastcall getFormIndex();
  	void __fastcall setFormIndex(int value);

		int  __fastcall	SetEditOrdinals(TWinControl *p);
		UnicodeString __fastcall FormatValue(UnicodeString value, int type);
		UnicodeString __fastcall RemoveChar(UnicodeString value, UnicodeString CharValue);

		int  __fastcall GetEnabledFromVector(int dbOrdinal);
		bool __fastcall ValidDecimalValue(TControl * ctrl);
		void __fastcall GetEditControlsOrder(TWinControl *p);

		/* private methoods */
		int  __fastcall ExistsControlOrder(std::vector<TSQLiteFieldProp*>& Fields, int order);
		int  __fastcall GetFirstOrder(TWinControl *p);
		int  __fastcall GetNextFocus(TWinControl * ctrl);
		int __fastcall GetPreviousFocus(TWinControl * ctrl);
		int  __fastcall GetOrdinalByFieldOrder(int index);
		bool __fastcall IncludeField(int ordinal);
		bool __fastcall IsProtected(TControl *ctrl);

		void __fastcall setFocusFields(int first);
		void __fastcall SetFontStyle(TLabel *l, bool enabled);
//		void __fastcall ShowRecord(TLOdbcCon *db, TWinControl *p);
		void __fastcall SortFieldsVector();
		void __fastcall SortVector(std::vector<TSQLiteFieldProp*>& v);

		/* Vectors*/
		std::vector<TSQLiteFieldProp *> FocusFields;
		std::vector<int> numkeys;
		std::vector<TSQLiteParameters*> Params;

		void __fastcall ClearVectors();
		void __fastcall SetFields(TWinControl *p);
		TSQLiteAgentGetColDefs FColDefLoaded;
		TSQLiteAgentFieldFocusedEvent FOnFocusedField;
		TSQLiteAgentSetRecordEvent FOnSetRecord;
		TSQLiteAgentSetValueErrorEvent FOnBindValueError;

	protected:
		TColor FEnabled;
		TColor FDisabled;
		TColor FFieldDisabled;
		TColor FFieldEnabled;
		worker<UnicodeString> *w;

		void __fastcall SetBiDiMode();

		__property int Biggest = { read = getBiggest, write = setBiggest };
		__property int Smallest = { read = getSmallest, write = setSmallest };

	public:
		TSQLiteEdit* e;
		TSQLiteComboBox* c;
		TSQLiteDateTimePicker* dt;
		std::vector<TSQLiteFieldProp*> Fields;
		std::vector<TSQLiteFieldsFilter*> FieldsFilter;
		std::vector<TSQLiteEdit*> Edit;
		UnicodeString txt;
		int editMode;
		bool showingRecord;
		bool CancelOperation;
		Classes::TNotifyEvent DoNotify;
		UnicodeString msg, tmp;

		__fastcall TSQLiteAgent(TComponent* Owner);
		__fastcall ~TSQLiteAgent();

		TDateTime __fastcall SetDate(UnicodeString value);
		TTreeNode * __fastcall ParentNodeFromLevel(TTreeNode *n , int parentLevel);

		void __fastcall AssignEntryOrder(TWinControl *p);
		void __fastcall ButtonState(bool state);
//		bool __fastcall CheckComboItemInDatabase(TLOdbcCon *d, TSQLiteComboBox *cb);
//		bool __fastcall CheckComboItemInDatabase(TLOdbcCon *d, 	TSQLiteComboBox *cb, UnicodeString sql, UnicodeString notfoundMsg);
		void __fastcall ClearEdits(TWinControl *p);
		void __fastcall ClearEdits(TWinControl *p, UnicodeString defaultValue);
		void __fastcall ClearValues();
		UnicodeString __fastcall DateToSqlString(TDateTime dt);
		UnicodeString __fastcall DateTimeToSqlString(TDateTime dt);
		int __fastcall GetControlOrder(TWinControl *p);
		void __fastcall GetFocusFields(TStringList& sl);

//		void __fastcall FillRecord(TLOdbcCon *db, TWinControl *p, UnicodeString sql);
//		void __fastcall FillRecord(TLOdbcCon *db, UnicodeString sql);
//		void __fastcall FocusFieldState(bool enabled);
//		void __fastcall FocusFieldState(bool enabled, bool focusfirst);
		bool __fastcall GetColDef(TSQLite *db, UnicodeString cat, UnicodeString colName);
		bool __fastcall GetColDef(TSQLite *db, UnicodeString cat, UnicodeString colName, TWinControl *p);
		UnicodeString __fastcall GetDefaultFieldValue(UnicodeString fieldName);
		void __fastcall GetControlsEntryOrder(TWinControl *p);
		UnicodeString __fastcall FieldValueByDataType(UnicodeString value, int DataType);

		void __fastcall IsActive();
		void __fastcall PrepairAdd(TWinControl *p, TWinControl *ctrl);
		void __fastcall PrepairAdd(TWinControl *p);
		void __fastcall PrepairEdit(TWinControl *p);
		void __fastcall PrepairEdit(TWinControl *p, TWinControl *ctrl);
		void __fastcall ReloadCurrent();
		void __fastcall SetFocus(TObject  *Sender, TWinControl *p, TWinControl *focusOn);
		void __fastcall SetFocusPrevious(TObject *Sender, TWinControl *p,	TWinControl *focusOn);

//		UnicodeString __fastcall GetFieldValue(TLOdbcCon *db,UnicodeString sql);
		UnicodeString __fastcall GetValueByFieldName(UnicodeString FieldName);
		int __fastcall GetDataTypeByFieldName(UnicodeString FieldName);
		UnicodeString __fastcall InjectSqlValues(UnicodeString sql, UnicodeString field, UnicodeString value, bool insert);
		UnicodeString __fastcall MakeSql(TWinControl *p, UnicodeString table, UnicodeString where, bool insert);
		UnicodeString __fastcall MakeSqlAllFields(TWinControl *p, UnicodeString table, UnicodeString where, bool insert);
		UnicodeString __fastcall PrettyText(UnicodeString s, TSQLiteEdit *e);
		UnicodeString __fastcall PrettyText(UnicodeString s);

		UnicodeString __fastcall SetFormTitle(UnicodeString title);

		int  __fastcall GetIndexByFieldName(UnicodeString FieldName);

//		bool __fastcall ExecuteSql(TLOdbcCon * db, UnicodeString sql, bool RollBack);
//		bool __fastcall SetRecordValues(TLOdbcCon *db, TWinControl *p);
		bool __fastcall SetFieldValueByName(UnicodeString field, UnicodeString value);
		void __fastcall SetFieldOrdinals(TControl *ctrl, bool enabled);
		void __fastcall ShowDatabaseDefaults(TWinControl *p);

		UnicodeString __fastcall SqlValue(UnicodeString value);
		UnicodeString __fastcall IsNumeric(bool decimalnumbersOnly,UnicodeString Key);
		void __fastcall ShowHints(bool showHelp, bool disableHints);
		void __fastcall DisableHints(bool show);
		void __fastcall SetHintsColors(	TControl *ctrl);
//to sort

		void __fastcall ExcludeFields(UnicodeString value, TWinControl *p);
		void __fastcall IncludeFields(UnicodeString value, TWinControl *p);
		void __fastcall StandAloneDataEntryFields(TWinControl *p, UnicodeString value);
//		void __fastcall Split(UnicodeString s, UnicodeString delim, TStringList& sl);
		void __fastcall DisableFields(TWinControl *p);
		void __fastcall SetFocusFirst();
		void __fastcall SetFocusFirst(int index);
		void __fastcall LoadTheImage(Vcl::Extctrls::TImage *img, UnicodeString file);
		void __fastcall PixelFormat(TPixelFormat *pf, TLabel* lpf);

		__property TSQLiteFormsAgent* FormsAgent = { read = getFormsAgent, write = setFormsAgent };
		__property TSQLite *SQLite = {read = getSqlite, write = setSqlite};

//		__property TLOdbcCon* CurDb = { read = getCurDb, write = setCurDb };
		__property TWinControl* CurP = { read = getCurP, write = setCurP };
		__property UnicodeString CurSql = { read = getCurSql, write = setCurSql };
		__property TTreeNode* ParentNode = { read = getParentNode, write = setParentNode };
		__property TTreeNode* SelectedNode = { read = getSelectedNode, write = setSelectedNode };
		__property TTreeNode * NodeToExpand = {read= getNodeToExpand, write = setNodeToExpand};
		__property UnicodeString ExpandNode = { read = getExpandNode, write = setExpandNode };
		__property int ParentNodeId = { read = getParentNodeId, write = setParentNodeId };

	__published:
//			__property TSQLite *SQLite = {read = getSqlite, write = setSqlite};
		__property TForm* Owner = { read = getOwner, write = setOwner };
		__property TCustomButton* AddButton = { read = getAdd, write = setAdd };
		__property TCustomButton* EditButton = { read = getEdit, write = setEdit };
		__property TCustomButton* SaveButton = { read = getSave, write = setSave };
		__property TCustomButton* DeleteButton = { read = getDel, write = setDel };
		__property TCustomButton* CancelButton = { read = getCancel, write = setCancel };
		__property TCustomButton* ExitButton = { read = getExit, write = setExit };
		__property TSQLiteAgent* Linktoagent = { read = getLinktoagent, write = setLinktoagent };
		__property TObject* Object = { read = getObject, write = setObject };
		__property TSQLiteHintPanel* HintPanel = { read = getHintPanel, write = setHintPanel };
		__property TColor HintBg = { read = getHintBg, write = setHintBg };
		__property TColor HintFg = { read = getHintFg, write = setHintFg };
		__property UnicodeString Floatformat = { read = getFloatformat, write = setFloatformat };

		__property UnicodeString SqlSelect = {read= getSqlSelect, write = setSqlSelect};
		__property UnicodeString SqlInsert = {read= getSqlInsert, write = setSqlInsert};
		__property UnicodeString SqlLoad = {read= getSqlLoad, write = setSqlLoad};
		__property UnicodeString SqlUpdate = {read= getSqlUpdate, write = setSqlUpdate};
		__property UnicodeString SqlDelete = {read= getSqlDelete, write = setSqlDelete};

		__property UnicodeString Title = { read = getTitle, write = setTitle };
		__property UnicodeString ClassName = { read = getClassName, write = setClassName };
		__property UnicodeString Data = { read = getData, write = setData };
		__property UnicodeString Group = { read = getGroup, write = setGroup };
		__property bool FormCreated = { read = getFormCreated, write = setFormCreated };
		__property bool CaptionIsTitle = { read = getCaptionIsTitle, write = setCaptionIsTitle };
		__property bool RecordSaved = { read = getRecordSaved, write = setRecordSaved };
		__property bool NewRecord = { read = getNewRecord, write = setNewRecord };
		__property bool Closing = { read = getClosing, write = setClosing };

		__property int FormIndex = { read = getFormIndex, write = setFormIndex };
		__property int RecordId = { read = getRecordId, write = setRecordId };
		__property int FieldCount = { read = getFieldCount, write = setFieldCount };
		__property int Lastfieldorder = { read = getLastfieldorder, write = setLastfieldorder };
		__property int Last = { read = getLast, write = setLast };

		__property TColor LabelEnabled = {read = getLabelEnabled, write = setLabelEnabled};
		__property TColor LabelDisabled = {read = getLabelDisabled, write = setLabelDisabled};
		__property TColor FieldEnabled = {read = getFieldEnabled, write = setFieldEnabled};
		__property TColor FieldDisabled = {read = getFieldDisabled, write = setFieldDisabled};
		__property UnicodeString FloatFormat = {read = getFloatFormat, write = setFloatFormat};
		__property TColor HintBackgroundColor = {read=getHintBackgroundColor, write = setHintBackgroundColor};
		__property TColor HintForeGroundColor = {read = getHintForeGroundColor, write=setHintForeGroundColor};
		__property int OwnerFormIndex = {read = getFormIndex, write = setFormIndex};
		__property TSQLiteAgentGetColDefs OnColDefsLoaded={read=FColDefLoaded, write=FColDefLoaded};
		__property TSQLiteAgentFieldFocusedEvent OnFocusedField ={read=FOnFocusedField, write =FOnFocusedField};
		__property TSQLiteAgentSetRecordEvent OnSetRecordValues ={read=FOnSetRecord, write=FOnSetRecord};
		__property TSQLiteAgentSetValueErrorEvent OnBindValueError  ={read=FOnBindValueError, write=FOnBindValueError};
		__property bool EnableHints = { read = getEnableHints, write = setEnableHints };

	};
// ---------------------------------------------------------------------------------
#endif
rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

theLizard wrote: Tue Apr 06, 2021 6:15 pm The following is th .h file for the other component
You have a circular dependency problem. TSqliteAgent.h #include's TSqliteComponent.h, and TSqliteComponent.h #include's TSqliteAgent.h. So you end up in a situation where the TSQLite class has not actually been defined yet when the compiler tries to compile the failing __property in TSQLiteAgent, hence the "not an allowed type" error.

The solution for solving this kind of dependency problem is to use forward-declarations. For instance, several of the #include's in TSqliteComponent.h need to be moved to TSqliteComponent.cpp, and same with TSqliteAgent.h and TSqliteAgent.cpp, and then any cross-unit class references need to be forward-declared as needed. TSqliteComponent.h and TSqliteAgent.h do not need to know what those classes actually look like in order to declare pointers to them.

In the case of a published __property declaration involving a forward-declared class type, you need to mark the forward-declaration with __declspec(delphiclass).

I have a suspicion that your other TSql... .h/.cpp files probably suffer from this same issue.

So, for example:

TSqlComponent.h

Code: Select all

//---------------------------------------------------------------------------

#ifndef TSqliteComponentH
#define TSqliteComponentH
//---------------------------------------------------------------------------
...
#include "sqlite3.h"
//#include "sqlite3ext.h"

// forward declarations
class TSQLiteOperations;
class TSQLiteParameters;
class __declspec(delphiclass) TSQLiteTreeView;
class TSQLiteAgent;
class TSQLiteComboBox;

...

//---------------------------------------------------------------------------
class PACKAGE TSQLite : public TComponent
	{
	...
	};
//---------------------------------------------------------------------------
class TBaseRecord
	{
	...
	};
//---------------------------------------------------------------------------
class TDBRecords
	{
	...
	};
//---------------------------------------------------------------------------
#endif
TSqliteComponent.cpp:

Code: Select all

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TSqliteComponent.h"

// moved here
#include "TSQLiteOperations.h"
#include "TSQLiteParameters.h"
#include "TSQLiteTreeView.h"
#include "TSQLiteAgent.h"
#include "TSQLiteComboBox.h"

...
TSqliteAgent.h

Code: Select all

#ifndef TSQLiteAgentH
#define TSQLiteAgentH
// ---------------------------------------------------------------------------------
...
// forward declarations
class TSqliteComponent;
class __declspec(delphiclass) TSQLite;
class TSQLiteEdit;
class TSQLiteComboBox;
class TSQLiteCheckListBox;
class TSQLiteFieldsFilter;
class TSQLiteFieldProp;
class TSQLiteFormsAgent;
class TSQLiteDateTimePicker;
class TSQLiteMemo;
class TSQLiteCheckBox;
class __declspec(delphiclass) TSQLiteHintPanel;
class TSQLiteIncludes;
class TSQLiteListBox;
class TSQLiteParameters;

// ---------------------------------------------------------------------------------
class PACKAGE TSQLiteAgent : public TComponent
	{
	...
	};
// ---------------------------------------------------------------------------------
#endif
TSqliteAgent.cpp:

Code: Select all

//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TSqliteAgent.h"

// moved here
#include "TSqliteComponent.h"
#include "TSQLiteEdit.h"
#include "TSQLiteComboBox.h"
#include "TSQLiteCheckListBox.h"
#include "TSQLiteFieldsFilter.h"
#include "TSQLiteFieldProp.h"
#include "TSQLiteFormsAgent.h"
#include "TSQLiteDateTimePicker.h"
#include "TSQLiteMemo.h"
#include "TSQLiteCheckBox.h"
#include "TSQLiteHintPanel.h"
#include "TSQLiteIncludes.h"
#include "TSQLiteListBox.h"
#include "TSQLiteParameters.h"

...
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

rlebeau wrote: Tue Apr 06, 2021 7:01 pm You have a circular dependency problem.
I thought that was the case, but was not sure how to resolve it, will go and make the changes as suggested and you are right, my other files will suffer from the same issue will blame it on bad habit and not fully understanding things as they should be.

Cheers
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

Thanks Remy,

Your help is very much appreciated, your suggestion has done the trick so, now off to fix all the other components with the same issue.
rlebeau wrote: Tue Apr 06, 2021 5:31 pmlogic errors
If you have a moment, could you point to an area where this is an issue and suggest a fix so that I can learn a bit more, always willing..

Cheers
rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

theLizard wrote: Tue Apr 06, 2021 7:41 pm If you have a moment, could you point to an area where this is an issue and suggest a fix so that I can learn a bit more, always willing..
Here we go (there are a LOT of them):

Code: Select all

TDBRecords* q;
TBaseRecord* r;
char *_ident;
std::vector<TBaseRecord*> rc;
std::vector<TDBRecords*> qr;  //for database table records
std::vector<TDBRecords*> qp;  //for field properties called by pragma
std::vector<TDBRecords*> tn; 	//used to get table names from sqlite_master
int get;
Why so many global variables? Why are they not class members, or in many cases even just local variables? You don't need to share these variables across multiple instances of your component, so they should not be global.

I also noticed that there are a lot of class data members being used that really should be local variables instead. Don't bloat your classes unnecessarily with data that doesn't need to persist across method calls.

Code: Select all

static int selectcallback(void *data, int argc, char **argv, char **azColName)
Suffers from several memory leaks if an exception is thrown unexpectedly. Also leaks the TDBRecords object if no TBaseRecords objects are added to it.

Code: Select all

sqlite3 * __fastcall TSQLite::Open(const char *file)
sqlite3 * __fastcall TSQLite::Open16(const char *file)
sqlite3 * __fastcall TSQLite::OpenV2(const char *file, int flags,/* Flags */ const char *zVfs)
No error handling on sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). I would throw an exception if they fail.

Code: Select all

void __fastcall TSQLite::Close(sqlite3 *_db)
void __fastcall TSQLite::CloseV2(sqlite3 *_db)
No need for separate methods that do the same thing. I would get rid of CloseV2() completely.

Code: Select all

int __fastcall TSQLite::Execute( char* sql)
int __fastcall TSQLite::Execute(UnicodeString sql)
Likewise, no need for separate methods that do the same thing. I would get rid of one of them completely. Otherwise, if you really need the two input types (which you don't), then just have one method call the other method after converting the data to that format.

Code: Select all

int __fastcall TSQLite::Execute( char* sql)
int __fastcall TSQLite::Execute(UnicodeString sql)
int __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
int __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)
All of these suffer from memory leaks when calling UnicodeToChar(), as it returns new[]'ed memory that needs to be delete[]'ed by the caller. A better design would be to have UnicodeToChar() return an AnsiString instead, and then you can use that string's c_str() method if needed.

For that matter, UnicodeToChar() and CharToUnicode() are completely unnecessary, as a UnicodeString can be assigned directly to an AnsiString, and a char* can be assigned directly to a UnicodeString.

Also, you should not use Application->MessageBox() inside a component, throw an exception instead and let the caller decide what to do with it.

Code: Select all

int __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
int __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)
Also, these are leaking TDBRecords objects.

Code: Select all

std::vector<TBaseRecord*>& __fastcall TSQLite::GetValuesByrecordId(int id)
If the requested ID is not found, this method still attempts to access into dbQueryResult, using an invalid index -1. There is no need to use an index at all since you have an iterator pointing at the found record, so just dereference that iterator instead. But more importantly, since the method returns a reference, and a reference can't be unassigned, then the only sane thing to do if the ID is not found is to throw an exception. Otherwise, change the method to return a pointer instead, and then you can return NULL on failure, but you will have to check for that NULL at every site where GetValuesByrecordId() is called.

Code: Select all

UnicodeString __fastcall TSQLite::GetFieldValue(std::vector<TBaseRecord*>& r, UnicodeString col_name, int &_foundIndex)
Likewise, this method also suffers from bad use of index -1 on failure.

Code: Select all

char * __fastcall TSQLite::UnicodeToChar(UnicodeString s)
UnicodeString __fastcall TSQLite::CharToUnicode(char* str)
Just bad designs, for a number of reasons. Get rid of then completely, you don't need them.

Code: Select all

void __fastcall TSQLite::TableInfo(UnicodeString table)
Suffers from an SQL Injection attack. You are trusting the input to contain only a table name by itself, but you are not protecting against a malicious user calling TableInfo() with a malformed name that terminates the pragma statement and executes a completely different SQL statement that queries other areas of the database, or alters tables, or even destroys the database itself. ALWAYS validate and sanitize user input when building SQL statements by hand. Otherwise, use parameterized queries whenever possible.

Also, this method suffers from out of bounds errors when accessing qp[x]->br[1] and qp[x]->br[found+1], if br[] does not have 2+ records, or does not contain the requested prop.

Code: Select all

void __fastcall TSQLite::GetDatabaseTables()
Likewise, also suffers from the same out of bounds errors.

Code: Select all

UnicodeString __fastcall TSQLite::PropertyType(std::vector<TBaseRecord*>& r, UnicodeString name)
Not validating that GetFieldValue() is successful before using the returned index.

Code: Select all

void __fastcall TSQLite::FillComboBox(TSQLiteComboBox *c, UnicodeString sql, UnicodeString field)
Optional, but this method should call c->Items->BeginUpdate()/c->Items->EndUpdate() when altering the ComboBox, which will disable UI updates until the alterations are finished.

Code: Select all

bool __fastcall TSQLite::AddParameter(UnicodeString ColumnName, UnicodeString Value)
Suffers from a memory leak if an exception is thrown unexpectedly before the new Param is added to the list. Also, don't use Application->MessageBox() to report the new Param can't be added, throw an exception instead.

Code: Select all

bool __fastcall TSQLite::FindType(UnicodeString ColumnName, UnicodeString &value)
Out of bounds errors.

Code: Select all

bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value)
	{
  return(FindPropertyValue(ColumnName, value));
	}
This is creating an endless recursion loop, because the method is calling itself over and over. Did you mean to call the overloaded FindPropertyValue() that takes a 3rd 'int _property' parameter?

Code: Select all

bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value, int _property)
Out of bounds errors.

Code: Select all

int __fastcall TSQLite::Prepair(sqlite3 *_db, UnicodeString s)
Memory leak on UnicodeToChar(), and also leaking the TSQLiteOperations object before exiting.

Also, if sqlite3_prepare_v2() fails, you should exit immediately, or throw an exception. Don't keep trying to process the invalid SQL statement.

Code: Select all

TTreeNode* __fastcall TSQLite::ShowProptiesInTreeView()
TTreeNode* __fastcall TSQLite::ShowQueryResultsInTreeView()
TTreeNode* __fastcall TSQLite::ShowSQLiteMasterQueryResultsInTreeView()
Optional, but these methods should call TreeView->BeginUpdate()/TreeView->EndUpdate() when altering the TreeView, which will disable UI updates until the alterations are finished.

Also, presumably TSQLiteTreeNode derives from TTreeNode, in which case there is no need to dynamic_cast the 'root' variable to TTreeNode (if anything, static_cast would have been more appropriate). A pointer/reference to a descendant class can be assigned to a pointer/reference to a base class without using any cast at all.

Code: Select all

int __fastcall TSQLite::GetLastAutoIncrement(UnicodeString table)
Suffers from SQL Injection attack.
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

rlebeau wrote: Wed Apr 07, 2021 10:19 am Here we go (there are a LOT of them):
That went without saying :)

Okay, a preamble, I started on this project late March as a something to do to pass time which I have lots off but nowhere to go.

When I downloaded the SQLite amalgamation code in sqlite3.c, I wanted to see if it would compile in a project, it did without complaint so I thought, could I create a component that would retire my old version of sqlite db access via ODBC (will be going back to that older version and fix the forward-declaration issues I know I have there :) )

Clearly, there is a lot of learning to do with this, the aim is to get the component as clean as possible with all the checks and balances built in.

Most of the issues you have mentioned, and I appreciate that very much, are issues that I knew had to be addressed at some point in the evolution.

Some of the issues I would not have looked at and I genuinely thank you for pointing those out.
rlebeau wrote: Wed Apr 07, 2021 10:19 am Why so many global variables? Why are they not class members
These came as a result of the early stages of getting the info sent by the db to the callback, if I put them into the class I would get errors in compiling so made them global at the early stage to get things going.

I have made changes this morning as per your suggestion the following are still global, all other vars have been moved to the class or made local to the method, hop this is ok.

Code: Select all

std::vector<TDBRecords*> qr;  //for database table records
std::vector<TDBRecords*> qp;  //for field properties called by pragma
std::vector<TDBRecords*> tn; 	//used to get table names from sqlite_master
int get;

rlebeau wrote: Wed Apr 07, 2021 10:19 am Code: Select all

static int selectcallback(void *data, int argc, char **argv, char **azColName)

Suffers from several memory leaks if an exception is thrown unexpectedly. Also leaks the TDBRecords object if no TBaseRecords objects are added to it.
I am not sure about this one, if there is nothing returned from the database, nothing is done, in this case I assumed that the TDBRecords vectors qr, qp, tn are empty, is a memory leak situation, if so, I am not sure how to fix it.

If there is data, the TDBRecords vector would be given a new TBaseRecord made up of the data returned so unless, I think, there is some other factor unrelated, a base record should always be pushed back into the appropriate vector.

Code: Select all

//---------------------------------------------------------------------------
static int selectcallback(void *data, int argc, char **argv, char **azColName)
	{
	TDBRecords* q;
	TBaseRecord* r;

	int i, size = argc;

	if(size > 0)
		{
		q = new TDBRecords();
		q->id = -1;
		}

	for(i = 0; i < size; i++)
		{
		r = new TBaseRecord();

		if(i == 0)
			{
			switch(Load_Which)
				{
				case vTables:
					q->fieldName = "Table";  // was azColName[i];
					q->id = StrToInt(i);
					break;
				case vTableInfo:
				case vRecords:
					q->fieldName = azColName[i];
					q->id = StrToInt(argv[i]);
					break;
				}
			}
		r->c = azColName[i];
		r->v = argv[i] ? argv[i] : "NULL";

		q->br.push_back(r);
		}
		if(q->br.size() > 0)
			{
			switch(get)
				{
				case vTableInfo:
					qp.push_back(q);
					break;
				case vRecords:
					qr.push_back(q);
					break;
				case vTables:
					tn.push_back(q);
				}
			}
	return 0;
	}

rlebeau wrote: Wed Apr 07, 2021 10:19 am No error handling on sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). I would throw an exception if they fail.
Is this okay, it is what I would have done over the course of development, should it be something different.

Code: Select all

sqlite3 * __fastcall TSQLite::Open(const char *file)
	{
	//===================================================================================================
	// If Database files exists, it will open it
	// If file does not exist, it will create an empty Database file
	//===================================================================================================
	int rc;

	try
		{
		rc = sqlite3_open(file, &_db);
		}
	catch(const Exception& e)
		{
		throw ( Exception("Open Database: " + e.Message) );
		}

	return _db;
	}

rlebeau wrote: Wed Apr 07, 2021 10:19 am
void __fastcall TSQLite::Close(sqlite3 *_db)
void __fastcall TSQLite::CloseV2(sqlite3 *_db)

No need for separate methods that do the same thing. I would get rid of CloseV2() completely.
The code in CloseV2 should have been sqlite3_close_v2(_db);
rlebeau wrote: Wed Apr 07, 2021 10:19 am
int __fastcall TSQLite::Execute( char* sql)
int __fastcall TSQLite::Execute(UnicodeString sql)

Likewise, no need for separate methods that do the same thing. I would get rid of one of them completely. Otherwise, if you really need the two input types (which you don't), then just have one method call the other method after converting the data to that format.
Ok, see your point.
rlebeau wrote: Wed Apr 07, 2021 10:19 am All of these suffer from memory leaks when calling UnicodeToChar(), as it returns new[]'ed memory that needs to be delete[]'ed by the caller. A better design would be to have UnicodeToChar() return an AnsiString instead, and then you can use that string's c_str() method if needed.

For that matter, UnicodeToChar() and CharToUnicode() are completely unnecessary, as a UnicodeString can be assigned directly to an AnsiString, and a char* can be assigned directly to a UnicodeString.

Also, you should not use Application->MessageBox() inside a component, throw an exception instead and let the caller decide what to do with it.
Ditto, will make necessary changes.
rlebeau wrote: Wed Apr 07, 2021 10:19 am
int __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
int __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)

Also, these are leaking TDBRecords objects.
I don't understand how?
rlebeau wrote: Wed Apr 07, 2021 10:19 am If the requested ID is not found, this method still attempts to access into dbQueryResult, using an invalid index -1.
My bad..
rlebeau wrote: Wed Apr 07, 2021 10:19 am Just bad designs, for a number of reasons. Get rid of then completely, you don't need them.
Ok.
rlebeau wrote: Wed Apr 07, 2021 10:19 am Suffers from an SQL Injection attack. You are trusting the input to contain only a table name by itself, but you are not protecting against a malicious user calling TableInfo() with a
Early stages, the full intent is to use parameters which is the reason I have
rlebeau wrote: Wed Apr 07, 2021 10:19 am bool __fastcall TSQLite::AddParameter(UnicodeString ColumnName, UnicodeString Value)
Work in progress, a lot off in this case, it is one of the reasons that the TableInfo method is declared, need to get column types so that the proper parameter binding can be called in int __fastcall TSQLite::Prepair(sqlite3 *_db, UnicodeString s)

At the completion, not that anything is ever really complete, there will be little chance of an sql injection unless it is done by the component itself and not from the outside world.

Rather than respond to the other issues, can I post back the code for the component after all changes have been made for you to look at :)

Lot's of work to do here.

Cheers
rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

theLizard wrote: Wed Apr 07, 2021 4:59 pm the following are still global, all other vars have been moved to the class or made local to the method, hop this is ok.

Code: Select all

std::vector<TDBRecords*> qr;  //for database table records
std::vector<TDBRecords*> qp;  //for field properties called by pragma
std::vector<TDBRecords*> tn; 	//used to get table names from sqlite_master
int get;
I see no reason for them to be global at all. They should be local to whichever method(s) are actually performing SQL queries.

And even then, you actually don't even need those temporary vectors, you can use the 'data' parameter of selectcallback() to pass the desired target vector into the callback so it knows exact which vector to populate with records. Let the caller of sqlite3_exec() decide which vector to use based on the kind of query it is performing. So, that elimiates those 4 global variables altogether.
theLizard wrote: Wed Apr 07, 2021 4:59 pm
rlebeau wrote: Wed Apr 07, 2021 10:19 am No error handling on sqlite3_open(), sqlite3_open16(), or sqlite3_open_v2(). I would throw an exception if they fail.
Is this okay
No, it should look more like this instead:

Code: Select all

int rc = sqlite3_open(file, &_db);
if (rc != SQLITE_OK)
    throw Exception("Open Database failed. Error " + String(rc));
theLizard wrote: Wed Apr 07, 2021 4:59 pm
rlebeau wrote: Wed Apr 07, 2021 10:19 am
int __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
int __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)

Also, these are leaking TDBRecords objects.
I don't understand how?
Both SelectSql() overloads are creating a TDBRecord object before executing the SQL query. Regardless of whether the query returns any records, you are not freeing that object before exiting.
theLizard wrote: Wed Apr 07, 2021 4:59 pm Rather than respond to the other issues, can I post back the code for the component after all changes have been made for you to look at :)
I would suggest something more like the following (I guarantee nothing! I may have missed some things along the way):

.h

Code: Select all

//---------------------------------------------------------------------------

#ifndef TSqliteComponentH
#define TSqliteComponentH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <windows.h>
#include <StrUtils.hpp>

#include <vector>
#include <algorithm>

#include "sqlite3.h"
//#include "sqlite3ext.h"

class TSQLiteOperations;
class TSQLiteParameters;
class TSQLiteAgent;
class TSQLiteComboBox;
class __declspec(delphiclass) TSQLiteTreeView;

enum loadwhich {vRecords, vTableInfo, vTables};
enum pProperty {pColtype, pNotNull, pDflt_Value, pPk};

#define SQLITE_TABLE "SELECT * FROM sqlite_master ORDER BY type"

//---------------------------------------------------------------------------
struct TBaseRecord
	{
	//===================================================================================================
	// storage for each column returned by an select a statement
	// example:
	//		sql = "SELECT * FROM MAKE";  gets all columns from table make.
	//===================================================================================================
	String c; // column name
	String v; // value
	String t; // column type
	String l; // column length
	};
//---------------------------------------------------------------------------
struct TDBRecords
	{
	//===================================================================================================
	// vector of all record values returned from database sql query
	//
	//===================================================================================================
	String fieldName; 	// column name
	int id;
	std::vector<TBaseRecord> br;
	};
//---------------------------------------------------------------------------
class PACKAGE TSQLite : public TComponent
	{
	friend class TBaseRecord;
	friend class TDBRecords;
	friend class TSQLiteComboBox;
	friend class TSQLiteTreeView;
	friend class TSQLiteAgent;

	private:
		sqlite3 *_db;

		String _dbSource;
		std::vector<TDBRecords> dbQueryResult;
		std::vector<TDBRecords> dbPropertyResult;
		std::vector<TDBRecords> dbTablesResult;

		String __fastcall getDatabaseSource();
		void __fastcall setDatabaseSource(String value);

		TSQLiteTreeView* _tv;
		String _tableName;

		void __fastcall setTv(TSQLiteTreeView* tv);
		TSQLiteTreeView* __fastcall getTv();

	protected:
		TSQLiteOperations* ops;

	public:
		__fastcall TSQLite(TComponent* Owner);
		__fastcall ~TSQLite();

		TTreeNode* __fastcall ShowProptiesInTreeView();
		TTreeNode* __fastcall ShowQueryResultsInTreeView();
		TTreeNode* __fastcall ShowSQLiteMasterQueryResultsInTreeView();
		int __fastcall GetLastAutoIncrement(String table);

		std::vector<TBaseRecord>& __fastcall GetValuesByrecordId(int id);
		std::vector<TDBRecords>& __fastcall FieldProps();
		std::vector<TDBRecords>& __fastcall FieldValues();
		std::vector<TSQLiteParameters*> Params;

		void __fastcall Open();
		void __fastcall Open16();
		void __fastcall OpenV2(int flags, String zVfs);
		void __fastcall Close();
		void __fastcall CloseV2();

		void __fastcall TableInfo(String table);

		void __fastcall SelectSql(String sql, String _id, int _get);
		void __fastcall SelectSql(String sql, int _get);
		void __fastcall Execute(String sql);

		String __fastcall PropertyType(std::vector<TBaseRecord>& r, String name);
		String __fastcall GetFieldValue(std::vector<TBaseRecord>& r, String col_name, int &_foundIndex);
		int __fastcall GetPropFieldValue(std::vector<TBaseRecord>& r, String col_name);
		String __fastcall ValueType(String colName, std::vector<TBaseRecord>& r);
		String __fastcall GetValuesByrecordId(int id, String col_name);

		void __fastcall FillComboBox(TSQLiteComboBox* c, String sql, String field);
		int __fastcall Prepair(String sql);
		bool __fastcall AddParameter(String ColumnName, String Value);
		bool __fastcall FindType(String _column_name, String &value);

		bool __fastcall FindPropertyValue(String ColumnName, String &value, int _property);
		bool __fastcall FindPropertyValue(String ColumnName, String &value);
		void __fastcall ClearParameters();
		void __fastcall GetDatabaseTables();

	__published:
		__property String DBPath = {read=getDatabaseSource, write=setDatabaseSource};
		__property TSQLiteTreeView* __fastcall TreeView = {read = getTv, write = setTv};
	};
//---------------------------------------------------------------------------
#endif
.cpp

Code: Select all

 
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TSqliteComponent.h"

#include <iostream>
#include <memory>

#include "TSQLiteOperations.h"
#include "TSQLiteParameters.h"
#include "TSQLiteTreeView.h"
#include "TSQLiteAgent.h"
#include "TSQLiteComboBox.h"

#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
//      SQLite info Website's
//      https://www.sqlite.org/quickstart.html
//      https://www.sqlite.org/cintro.html
//			https://www.tutorialspoint.com/sqlite/sqlite_c_cpp.htm
//
//===================================================================================================
//===================================================================================================
__fastcall TSQLite::~TSQLite()
	{
	}
//---------------------------------------------------------------------------
struct IsColName
	{
	String _colName;

	IsColName(String colName) : _colName(colName) {}
	bool operator()(const TBaseRecord &item) const
		{
		return (item.c == _colName);
		}
	};
//---------------------------------------------------------------------------
struct IsPropColName
	{
	String _propColName;

	IsPropColName(String propColName) : _propColName(propColName) {}
	bool operator()(const TBaseRecord &item) const
		{
		return (item.v == _propColName);
		}
	};
//---------------------------------------------------------------------------
struct IsId
	{
	int _id;

	IsId(int id) : _id(id) {}
	bool operator()(const TDBRecords &item) const
		{
		return (item.id == _id);
		}
	};
//---------------------------------------------------------------------------
static int logCallback(void*, int argc, char **argv, char **azColName)
	{
	for(int i = 0; i < argc; ++i)
		{
		std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << '\n';
		}
	std::cout << '\n';
	return 0;
}
//---------------------------------------------------------------------------
struct selectData
	{
	int get;
	std::vector<TDBRecords> *results;
	};

static int selectCallback(void *data, int argc, char **argv, char **azColName)
	{
	//===================================================================================================
	//
	//
	//
	//===================================================================================================

	selectData pData = static_cast<selectData*>(data);
	if (pData->results)
		{
		TDBRecords q;
		q.id = -1;

		if (argc > 0)
			{
			switch (pData->get)
				{
				case vTables:
					q.fieldName = "Table";  // was azColName[i];
					q.id = 0;
					break;
				case vTableInfo:
				case vRecords:
					q.fieldName = azColName[0];
					q.id = StrToInt(argv[0]);
					break;
				}

			q.br.reserve(argc);

			for(int i = 0; i < argc; ++i)
				{
				TBaseRecord r;

				r.c = azColName[i];
				r.v = argv[i] ? argv[i] : "NULL";

				q.br.push_back(r);
				}
			}

		pData->results->push_back(q);
		}

	return 0;
	}
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TSQLite *)
	{
	new TSQLite(NULL);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Open()
	{
	//===================================================================================================
	// If Database files exists, it will open it
	// If file does not exist, it will create an empty Database file
	//===================================================================================================

	int rc = sqlite3_open(UTF8String(DBPath).c_str(), &_db);
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + String(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Open16()
	{
	int rc = sqlite3_open16(DBPath.c_str(), &_db);
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + String(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::OpenV2(int flags, String zVfs)
	{
	// refer https://www.sqlite.org/vfs.html for *zVfs parameter
	int rc = sqlite3_open_v2(UTF8String(DBPath).c_str(), &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, static_cast<const char*>(UTF8String(zVfs).data()));
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + String(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Close()
	{
	if (_db)
		{
		sqlite3_close(_db);
		_db = NULL;
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::CloseV2()
	{
	if (_db)
		{
		sqlite3_close_v2(_db);
		_db = NULL;
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Execute(String sql)
	{
	//===================================================================================================
	//  execute the sql statement a the datbase
	//
	//  DBPath is a property of TSQLite, it must be set before executing any sql statement
	//      SQLite1->DBPath = drive\\path\\anydatabase.db
	//===================================================================================================

	/* Execute SQL statement */
	Open();

	char* zErrMsg = NULL;
	int rc = sqlite3_exec(_db, UTF8String(sql).c_str(), logCallback, NULL, &zErrMsg);
	if (rc != SQLITE_OK)
		{
		String s = zErrMsg;
		sqlite3_free(zErrMsg);
		Close();
		throw Exception("SQL execute failed. Error " + String(rc) + ": " + s);
		}

	Close();
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::SelectSql(String sql, String _id, int _get)
	{
	//===================================================================================================
	//  this function, via callback, fills a vector of 	std::vector<TDBRecords> qr
	//                                                  has properties of TDBRecords;
	//                                                      UnicodeString 	fieldName
	//                                                      int 						id
	//	which contains a vector of 											std::vector<TBaseRecord> rc
	//                                                  has properties of TBaseRecord;
	//                                                      UnicodeString   c, v, t, l
	//  callback function fills vector of returned records from database
	//  the vector contains colum name, column value and column type
	//  q.br[0].c
	//  q.br[0].v
	//===================================================================================================

	selectData data;
	data.get = _get;

	switch (_get)
		{
		case vRecords:
			dbQueryResult.clear();
			data.results = &dbQueryResult;
			break;
		case vTableInfo:
			dbPropertyResult.clear();
			data.results = &dbPropertyResult;
			break;
		case vTables:
			dbTablesResult.clear();
			data.results = &dbTablesResult;
			break;
		default:
			data.results = NULL;
			break;
		}

	Open();

	char *zErrMsg = NULL;
	int rc = sqlite3_exec(_db, UTF8String(sql).c_str(), selectCallback, &data, &zErrMsg);
	if (rc != SQLITE_OK)
		{
		String s = zErrMsg;
		sqlite3_free(zErrMsg);
		Close();
		throw Exception("SQL execute failed. Error " + String(rc) + ": " + s);
		}

	Close();
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::SelectSql(String sql, int _get)
	{
	SelectSql(sql, "", _get);
	}
//---------------------------------------------------------------------------
std::vector<TBaseRecord>& __fastcall TSQLite::GetValuesByrecordId(int id)
	{
	//===================================================================================================
	// this function finds and returns, if it exists, the vector of TBaseRecords in the TDBRecords vector.
	// TDBRecord has 2 properties, fieldName and id
	//    the vector, [std::vector<TBaseRecord> br;] stores the column data of the record set
	//    returned by a SELECT statement
	//
	// example call to this function;
	//	 br = sq->GetValuesByrecordId(5); get the vector of record values
	//	 sz = br[18].v;  extract the field value of interest from the record by the index of the field element
	//===================================================================================================

	std::vector<TDBRecords>::iterator found = std::find_if(dbQueryResult.begin(), dbQueryResult.end(), IsId(id));
	if (found == dbQueryResult.end())
		throw Exception("ID " + String(id) + " not found");
		
	return found->br;
	}
//---------------------------------------------------------------------------
String __fastcall TSQLite::GetValuesByrecordId(int id, String col_name)
	{
	//===================================================================================================
	// this function finds the field value of the column name being queried by it's record id
	// example call to this function;
	//      sz = SQLite1->GetValuesByrecordId(6, "pfactor");
	//===================================================================================================

	int notUsed;
	return GetFieldValue(GetValuesByrecordId(id), col_name, notUsed);
	}
//---------------------------------------------------------------------------
String __fastcall TSQLite::GetFieldValue(std::vector<TBaseRecord>& r, String col_name, int &_foundIndex)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i].br, _colName, found)
	//        UnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0].br, "pfactor", found);
	//===================================================================================================
	_foundIndex = -1;

	std::vector<TBaseRecord>::iterator found = std::find_if(r.begin(), r.end(), IsColName(col_name));
	if (found == r.end())
		return "Nothing found";

	_foundIndex = std::distance(r.begin(), found);
	return found->v;
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetPropFieldValue(std::vector<TBaseRecord>& r, String col_name)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i].br, _colName, found)
	//        UnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0].br, "pfactor", found);
	//===================================================================================================

	std::vector<TBaseRecord>::iterator found = std::find_if(r.begin(), r.end(), IsPropColName(col_name));
	if (found == r.end())
		return -1;

	return std::distance(r.begin(), found);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::TableInfo(String table)
	{
	//===================================================================================================
	//	SQLite request:  "pragma table_info(" + table + ")" to fill std::vector<TDBRecords> qp
	//          -------------------------------------------------
	//					cid,	name,	type,				notnull,	dflt_value,	pk
	//          -------------------------------------------------
	//					0,		id,		INTEGER,		0,				NULL,				1
	//
	// 	example of call to this function;
	//        SQLite1->TableInfo("Readings");
	//
	// 	qr = vector of records collection containing vector of returned record values
	// 	qp = vector of all field properties based on column name from table queried to abtain values of records in qr vector
	//    get column name  _colName
	//    interate through qr and get each vector of record
	//		if(qr[0].br[i].c == _colName) //match found
	//      {
	//      qr[0].br[i].v = qp[0].br[2].v;
	//			}
	//	qp[0].br[1].v = u"id"
	//	qp[0].br[2].v = u"INT[4]"
	//	qp[1].br[1].v = u"make"
	//	qp[1].br[2].v = u"VARCHAR"
	//	qp[2].br[1].v = u"year"
	//	qp[2].br[2].v = u"VARCHAR"
	//===================================================================================================

	_tableName = table;

	SelectSql("pragma table_info(" + table + ")", "cid", vTableInfo);

	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)						// loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];
		String _colName = q.br[1].v;  					//assign column name to var
		int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type
		q.br[1].t = q.br[found+1].v;                 	//assign the field type to the base record field type for later use.
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::GetDatabaseTables()
	{
	SelectSql(SQLITE_TABLE, "cid", vTables);

	size_t c = dbTablesResult.size();
	for(size_t x = 0; x < c; ++x)						//loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbTablesResult[x];
		String _colName = q.br[1].v;  					//assign column name to var
		int found = GetPropFieldValue(q.br, _colName);	// find the index of the col def vector record containg the type
		q.br[1].t = q.br[found+1].v;                 	//assign the field type to the base record field type for later use.
		}
	}
//---------------------------------------------------------------------------
String __fastcall TSQLite::PropertyType(std::vector<TBaseRecord>& r, String name)
	{
	//===============================================================================================
	// get the property type from vector of field values
	// example of call to this function;
	// 				sz = SQLite1->PropertyType(SQLite1->dbQueryResult[1].br, "pfactor");
	//===============================================================================================

	int found;
	GetFieldValue(r, name, found);	//find the index into the vector containg the type value of the column name

	if (found == -1)
		return "";

	return r[found].t;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::FillComboBox(TSQLiteComboBox *c, String sql, String field)
	{
	//===============================================================================================
	//  This function fills a TSQLiteComboBox *c with values defined by the field parameter in the call.
	//
	//  sql contains the sql select statement to be executed
	//  field is the databse column name in the returned data set
	//
	// example of call to this function;
	//    SQLite1->FillComboBox(cb_Location , sql, "column_name");
	//
	//===============================================================================================
	c->Clear();

	//===============================================================================================
	// 	recordsId is a vector of database record id's matched to the combo items strings
	//  this allows for retrieval of db record by it's record id from a combo box item.
	//  the RecordId property is set when the item in the combo box is selected
	//
	// 	example usage fro call to SQLite DB;
	//    sql = "SELECT * FROM table WHERE reordid = " + IntToStr(c->RecordId);
	//    SelectSql(sql, vRecords);
	//===============================================================================================
	c->recordIds.clear();

	SelectSql(sql, vRecords);

	for(size_t i = 0; i < dbQueryResult.size(); ++i)
		{
		int id = dbQueryResult[i].id;
		c->recordIds.push_back(id);
		c->Items->Add(GetValuesByrecordId(id, field));
		}
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords>& __fastcall TSQLite::FieldProps()
	{
	return dbPropertyResult;
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords>& __fastcall TSQLite::FieldValues()
	{
	return dbQueryResult;
	}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::getDatabaseSource()
	{
	return _dbSource;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::setDatabaseSource(String value)
	{
	_dbSource = value;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::AddParameter(String ColumnName, String Value)
	{
	//
	if (dbPropertyResult.empty())
		throw Exception("Field types have not yet been obtained for parameter bindings");

	std::auto_ptr<TSQLiteParameters> param(new TSQLiteParameters);
	param->ColumnName = ColumnName;
	param->ParamName = "p" + IntToStr(Params.size());
	param->ParamValue = Value;

	String type;
	if (FindType(ColumnName, type))
		param->ColumnType = type; //get the column type from the qp vector using column name

	Params.push_back(param.get());
	param.release();
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindType(String ColumnName, String &value)
	{
	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)							// 	loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];

		String _colName = q.br[1].v;						//	assign column name to var

		if (_colName == ColumnName)          				//  compare vector element with ColumnName parameter
			{
			int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type
			value = q.br[found+1].v;                 		//assign the field type to the base record field type for later use.
			return true;
			}
		}

	return false;
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(String ColumnName, String &value)
	{
	return FindPropertyValue(ColumnName, value, 0);
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(String ColumnName, String &value, int _property)
	{
	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)							// 	loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];

		String _colName _colName = q.br[1].v;    			//	assign column name to var

		if (_colName == ColumnName)							//  compare vector element with ColumnName parameter
			{
			int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type

			switch (_property)
				{
				case pColtype:
					value = q.br[found+1].v;			//assign the field type to the base record field type for later use.
					break;
				case pNotNull:
					value = q.br[found+2].v;          	//assign the field type to the base record field type for later use.
					break;
				case pDflt_Value:
					value = q.br[found+3].v;          	//assign the field type to the base record field type for later use.
					break;
				case pPk:
					value = q.br[found+4].v;          	//assign the field type to the base record field type for later use.
					break;
				}

			return true;
			}
		}

	return false;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::ClearParameters()
	{
	for(size_t i = 0; i < Params.size(); ++i)
		delete Params[i];
	Params.clear();
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::Prepair(String sql)
	{
	if (!_db)
		throw Exception("Database not opened");

	sqlite3_stmt *stmt;
		
	int rc = sqlite3_prepare_v2(_db, UTF8String(sql).c_str(), -1, &stmt, NULL);
	if (rc != SQLITE_OK)
		throw Exception("SQL prepare failed. " + String(sqlite3_errmsg(_db)));

	//==========================================================================
	//  sqlite bind columns
	//
	//  bind colums based on column data type - use TableInfo( table name)
	//  to get data types for the bind process
	//
	//  possible method:   enum bindtype {tInt, ...};
	//										 Bind(int type, sqlite3_stmt *stmt, int valueCount, int value)
	//    rc = sqlite3_bind_int( tInt, stmt, vgalueCount, value);
	//    Bind(tInt, stmt, valueCount, 2015);
	//    switch(type)
	//      {
	//      case tInt:
	// 				rc = sqlite3_bind_int(stmnt, 1, 2015);
	//      }
	//==========================================================================
	//	rc = sqlite3_bind_int(  test1, 1, 2015);
	//	rc = sqlite3_bind_int(  test1, 2, stat_time.tv_sec);

	delete ops;
	ops = new TSQLiteOperations;

	rc = ops->Bind(tText, stmt, 1, "NH46034");

	do
		{
		rc = sqlite3_step(stmt);

		switch (rc)
			{
			/**  SQLITE_DONE  101 -- sqlite3_step() has finished executing  */
			case SQLITE_DONE:
				break;

			 /** New data */
			case SQLITE_ROW:
				{
				uint16_t size = sqlite3_column_count(stmt);
				if (size == 1) // should always be one
					{
					double value = sqlite3_column_double(stmt, 0);
					std::cout << "test 1 = " << value << ' ' << sqlite3_column_text(stmt, 0) << '\n';
					}
				}
				break;

			default:
				break;
			}
		}
	while (rc == SQLITE_ROW);

	return rc;
	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowProptiesInTreeView()
	{
	TreeView->ClearNodes();

	TSQLiteTreeNode *root = TreeView->AddRoot(TreeView->o, "Table Name: " + _tableName);

	for(size_t i = 0; i < dbPropertyResult.size(); ++i)
		{
		TDBRecords &q = dbPropertyResult[i];

		if (!q.br.empty())
			{
			TSQLiteTreeNode *child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + q.br[0].v);

			for(size_t j = 1; j < q.br.size(); ++j)
				{
				TreeView->AddTreeNode(child, TreeView->o, "Column " + q.br[j].c + " : " + q.br[j].v);
				}
			}
		}

	return root;
	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowQueryResultsInTreeView()
	{
	TreeView->ClearNodes();

	TSQLiteTreeNode *root = TreeView->AddRoot(TreeView->o, "Query Result");

	for(size_t i = 0; i < dbQueryResult.size(); ++i)
		{
		TDBRecords &q = dbQueryResult[i];

		if (!q.br.empty())
			{
			TSQLiteTreeNode *child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + q.br[0].v);

			for(size_t j = 1; j < q.br.size(); ++j)
				{
				TreeView->AddTreeNode(child, TreeView->o, q.br[j].c + " : " + q.br[j].v);
				}
			}
		}

	return root;
	}
//---------------------------------------------------------------------------
TTreeNode* __fastcall TSQLite::ShowSQLiteMasterQueryResultsInTreeView()
	{
	TreeView->ClearNodes();

	TSQLiteTreeNode *root = TreeView->AddRoot(TreeView->o, "Query Result");

	for(size_t i = 0; i < dbTablesResult.size(); ++i)
		{
		TDBRecords &q = dbTablesResult[i];

		if (!q.br.empty())
			{
			TSQLiteTreeNode *child = TreeView->AddTreeNode(root, TreeView->o, "Row ID: " + q.br[0].v);

			for(size_t j = 1; j < q.br.size(); ++j)
				{
				TreeView->AddTreeNode(child, TreeView->o, q.br[j].c + " : " + q.br[j].v);
				}
			}
		}

	return root;
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetLastAutoIncrement(String table)
	{
	//  Get the last sequence AUTOINCREMENT number of a table for AUTOINCREMENT field if any.
	SelectSql("select seq from sqlite_sequence where name = " + QuotedStr(table), vRecords);

	if (!dbQueryResult.empty())
		return StrToInt(dbQueryResult[0].br[0].v);

	return -1;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::setTv(TSQLiteTreeView* tv)
	{
	_tv = tv;
	}
//---------------------------------------------------------------------------
TSQLiteTreeView* __fastcall TSQLite::getTv()
	{
	return _tv;
	}
//---------------------------------------------------------------------------
__fastcall TSQLite::TSQLite(TComponent* Owner)
	: TComponent(Owner)
		{
		}
//---------------------------------------------------------------------------
namespace Tsqlitecomponent
{
	void __fastcall PACKAGE Register()
	{
		TComponentClass classes[1] = {__classid(TSQLite)};
		RegisterComponents(L"SQLite", classes, 0);
	}
}
//---------------------------------------------------------------------------
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

Thanks Remy, that is a lot to digest but happy to do that and learn something new.

Ok, had a couple of errors but I got your code to compile, and installed the component but when I went to compile the test project with components on the form I get this error, tried to see what was going on but lost.

[ilink32 Error] Error: Unresolved external 'std::ios_base::flags() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::flags() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::fail() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::rdstate() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::width() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::good() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::char_traits<char>::to_int_type(const char&)' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::char_traits<char>::eof()' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::char_traits<char>::eq_int_type(const int&, const int&)' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::width(int)' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::getloc() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::locale::id::operator unsigned int()' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::_Locinfo::_Getlconv() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::_Locinfo::_Getfalse() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::_Locinfo::_Gettrue() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::locale::facet::_Incref()' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::ios_base::precision() const' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unresolved external 'std::char_traits<char>::assign(char *, unsigned int, char)' referenced from E:\DEV-BERLIN\BPI-LIB\SQLITE101.LIB|TSQLiteComponent
[ilink32 Error] Error: Unable to perform link

Can you advise on this one please.

Also, before seeing your suggested code, I did get parameter binding to work eliminating the sql injection problem which I had always intended to implement.

Cheers
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

Hi Remy,

have reverted to old code, all errors are gone so there is something in the your code that is throwing things out of kilter, tried to find what but no luck.

Will try to compile just the one unit and see what goes.
rlebeau
BCBJ Author
BCBJ Author
Posts: 1792
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: __property Not an allowed type in __published: section

Post by rlebeau »

theLizard wrote: Wed Apr 07, 2021 11:27 pm Ok, had a couple of errors but I got your code to compile, and installed the component but when I went to compile the test project with components on the form I get this error, tried to see what was going on but lost.
All of those failing symbols are from the standard C++ library, which you were already using via <vector> and <algorithm>. One thing I did change was to replace printf() from <stdio.h> with std::cout from <iostream>. All of those errors are related to things that std::cout uses. I don't know why that portion of the standard library is not being linked correctly but others are, especially since my use of std::cout should be isolated inside of your component package, so your test project shouldn't even care that the component is using std::cout internally.

Whatever. Go back to using printf() then, if you want to. That will solve the errors.

Personally, I would not suggest outputting such debug strings from inside the component at all, I would expose the strings via an event/callback and let the application decide how to display them. Or at least use OutputDebugString() instead, and let a tool like DebugView display them at runtime.
Remy Lebeau (TeamB)
Lebeau Software
theLizard
BCBJ Master
BCBJ Master
Posts: 468
Joined: Wed Mar 18, 2009 2:14 pm

Re: __property Not an allowed type in __published: section

Post by theLizard »

@Remy

I have commented out all refs to other components that threw compile errors far a stand alone TSQLiteComponent leaving only the code in your example.

I have compiled the component and installed without issues but when I drop the component on a form I get lots of unresolved external errors, I have set all the paths for includes, libs etc.

Note that I have compiled this in Builder 10.3 to make absolutely sure I was in an environment that could not be contaminated by other code in my Builder 10.1 setup.

This is the code that compiles and installs, I did have to make some changes though, String was replaced with either UnicodeString or AnsiString, would not compile otherwise, there is probably a good reason for why it did not :(

.cpp

Code: Select all


//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "TSQLiteComponent.h"

#include <iostream>
#include <memory>
#pragma package(smart_init)
//---------------------------------------------------------------------------
// ValidCtrCheck is used to assure that the components created do not have
// any pure virtual functions.
//
//      SQLite info Website's
//      https://www.sqlite.org/quickstart.html
//      https://www.sqlite.org/cintro.html
//			https://www.tutorialspoint.com/sqlite/sqlite_c_cpp.htm
//
//===================================================================================================
//===================================================================================================
__fastcall TSQLite::~TSQLite()
	{
	}
//---------------------------------------------------------------------------
struct IsColName
	{
	UnicodeString _colName;

	IsColName(UnicodeString colName) : _colName(colName) {}
	bool operator()(const TBaseRecord &item) const
		{
		return (item.c == _colName);
		}
	};
//---------------------------------------------------------------------------
struct IsPropColName
	{
	UnicodeString _propColName;

	IsPropColName(UnicodeString propColName) : _propColName(propColName) {}
	bool operator()(const TBaseRecord &item) const
		{
		return (item.v == _propColName);
		}
	};
//---------------------------------------------------------------------------
struct IsId
	{
	int _id;

	IsId(int id) : _id(id) {}
	bool operator()(const TDBRecords &item) const
		{
		return (item.id == _id);
		}
	};
//---------------------------------------------------------------------------
static int logCallback(void*, int argc, char **argv, char **azColName)
	{
	for(int i = 0; i < argc; ++i)
		{
		std::cout << azColName[i] << " = " << (argv[i] ? argv[i] : "NULL") << '\n';
		}
	std::cout << '\n';
	return 0;
}
//---------------------------------------------------------------------------
struct selectData
	{
	int get;
	std::vector<TDBRecords> *results;
	};
//---------------------------------------------------------------------------
static int selectCallback(void *data, int argc, char **argv, char **azColName)
	{
	//===================================================================================================
	//
	//
	//
	//===================================================================================================
	selectData *pData = static_cast<selectData*>(data);

	if (pData->results)
		{
		TDBRecords q;
		q.id = -1;

		if (argc > 0)
			{
			switch (pData->get)
				{
				case vTables:
					q.fieldName = "Table";  // was azColName[i];
					q.id = 0;
					break;
				case vTableInfo:
				case vRecords:
					q.fieldName = azColName[0];
					q.id = StrToInt(argv[0]);
					break;
				}

			q.br.reserve(argc);

			for(int i = 0; i < argc; ++i)
				{
				TBaseRecord r;

				r.c = azColName[i];
				r.v = argv[i] ? argv[i] : "NULL";

				q.br.push_back(r);
				}
			}

		pData->results->push_back(q);
		}

	return 0;
	}
//---------------------------------------------------------------------------
static inline void ValidCtrCheck(TSQLite *)
	{
	new TSQLite(NULL);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Open()
	{
	//===================================================================================================
	// If Database files exists, it will open it
	// If file does not exist, it will create an empty Database file
	//===================================================================================================

	int rc = sqlite3_open( DBPath.c_str(), &_db);
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + UnicodeString(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Open16()
	{
	int rc = sqlite3_open16(DBPath.c_str(), &_db);
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + UnicodeString(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::OpenV2(int flags, AnsiString zVfs)
	{
	// refer https://www.sqlite.org/vfs.html for *zVfs parameter
	int rc = sqlite3_open_v2(DBPath.c_str(), &_db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, zVfs.c_str() );
	if (rc != SQLITE_OK)
		throw Exception("Database open failed. Error " + UnicodeString(rc));
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Close()
	{
	if (_db)
		{
		sqlite3_close(_db);
		_db = NULL;
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::CloseV2()
	{
	if (_db)
		{
		sqlite3_close_v2(_db);
		_db = NULL;
		}
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::Execute(AnsiString sql)
	{
	//===================================================================================================
	//  execute the sql statement a the datbase
	//
	//  DBPath is a property of TSQLite, it must be set before executing any sql statement
	//      SQLite1->DBPath = drive\\path\\anydatabase.db
	//===================================================================================================

	/* Execute SQL statement */
	Open();

	char* zErrMsg = NULL;
	int rc = sqlite3_exec(_db, sql.c_str(), logCallback, NULL, &zErrMsg);
	if (rc != SQLITE_OK)
		{
		UnicodeString s = zErrMsg;
		sqlite3_free(zErrMsg);
		Close();
		throw Exception("SQL execute failed. Error " + UnicodeString(rc) + ": " + s);
		}

	Close();
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::SelectSql(UnicodeString sql, UnicodeString _id, int _get)
	{
	//===================================================================================================
	//  this function, via callback, fills a vector of 	std::vector<TDBRecords> qr
	//                                                  has properties of TDBRecords;
	//                                                      UnicodeUnicodeString 	fieldName
	//                                                      int 						id
	//	which contains a vector of 											std::vector<TBaseRecord> rc
	//                                                  has properties of TBaseRecord;
	//                                                      UnicodeUnicodeString   c, v, t, l
	//  callback function fills vector of returned records from database
	//  the vector contains colum name, column value and column type
	//  q.br[0].c
	//  q.br[0].v
	//===================================================================================================

	selectData data;
	data.get = _get;
	AnsiString str = sql;
	switch (_get)
		{
		case vRecords:
			dbQueryResult.clear();
			data.results = &dbQueryResult;
			break;
		case vTableInfo:
			dbPropertyResult.clear();
			data.results = &dbPropertyResult;
			break;
		case vTables:
			dbTablesResult.clear();
			data.results = &dbTablesResult;
			break;
		default:
			data.results = NULL;
			break;
		}

	Open();

	char *zErrMsg = NULL;
	int rc = sqlite3_exec(_db,  str.c_str(), selectCallback, &data, &zErrMsg);
	if (rc != SQLITE_OK)
		{
		UnicodeString s = zErrMsg;
		sqlite3_free(zErrMsg);
		Close();
		throw Exception("SQL execute failed. Error " + UnicodeString(rc) + ": " + s);
		}

	Close();
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::SelectSql(UnicodeString sql, int _get)
	{
	SelectSql(sql, "", _get);
	}
//---------------------------------------------------------------------------
std::vector<TBaseRecord>& __fastcall TSQLite::GetValuesByrecordId(int id)
	{
	//===================================================================================================
	// this function finds and returns, if it exists, the vector of TBaseRecords in the TDBRecords vector.
	// TDBRecord has 2 properties, fieldName and id
	//    the vector, [std::vector<TBaseRecord> br;] stores the column data of the record set
	//    returned by a SELECT statement
	//
	// example call to this function;
	//	 br = sq->GetValuesByrecordId(5); get the vector of record values
	//	 sz = br[18].v;  extract the field value of interest from the record by the index of the field element
	//===================================================================================================

	std::vector<TDBRecords>::iterator found = std::find_if(dbQueryResult.begin(), dbQueryResult.end(), IsId(id));
	if (found == dbQueryResult.end())
		throw Exception("ID " + UnicodeString(id) + " not found");

	return found->br;
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::GetValuesByrecordId(int id, UnicodeString col_name)
	{
	//===================================================================================================
	// this function finds the field value of the column name being queried by it's record id
	// example call to this function;
	//      sz = SQLite1->GetValuesByrecordId(6, "pfactor");
	//===================================================================================================

	int notUsed;
	return GetFieldValue(GetValuesByrecordId(id), col_name, notUsed);
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::GetFieldValue(std::vector<TBaseRecord>& r, UnicodeString col_name, int &_foundIndex)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i].br, _colName, found)
	//        UnicodeUnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0].br, "pfactor", found);
	//===================================================================================================
	_foundIndex = -1;

	std::vector<TBaseRecord>::iterator found = std::find_if(r.begin(), r.end(), IsColName(col_name));
	if (found == r.end())
		return "Nothing found";

	_foundIndex = std::distance(r.begin(), found);
	return found->v;
	}
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetPropFieldValue(std::vector<TBaseRecord>& r, UnicodeString col_name)
	{
	//===================================================================================================
	// this function finds the value of the field being queried in the record returned
	// by GetValuesByrecordId which MUST be called before any attempt to get values
	// from the record's vector
	// example call to this function;
	//        GetFieldValue(qr[i].br, _colName, found)
	//        UnicodeUnicodeString sz = SQLite1->GetFieldValue(sq->dbQueryResult[0].br, "pfactor", found);
	//===================================================================================================

	std::vector<TBaseRecord>::iterator found = std::find_if(r.begin(), r.end(), IsPropColName(col_name));
	if (found == r.end())
		return -1;

	return std::distance(r.begin(), found);
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::TableInfo(UnicodeString table)
	{
	//===================================================================================================
	//	SQLite request:  "pragma table_info(" + table + ")" to fill std::vector<TDBRecords> qp
	//          -------------------------------------------------
	//					cid,	name,	type,				notnull,	dflt_value,	pk
	//          -------------------------------------------------
	//					0,		id,		INTEGER,		0,				NULL,				1
	//
	// 	example of call to this function;
	//        SQLite1->TableInfo("Readings");
	//
	// 	qr = vector of records collection containing vector of returned record values
	// 	qp = vector of all field properties based on column name from table queried to abtain values of records in qr vector
	//    get column name  _colName
	//    interate through qr and get each vector of record
	//		if(qr[0].br[i].c == _colName) //match found
	//      {
	//      qr[0].br[i].v = qp[0].br[2].v;
	//			}
	//	qp[0].br[1].v = u"id"
	//	qp[0].br[2].v = u"INT[4]"
	//	qp[1].br[1].v = u"make"
	//	qp[1].br[2].v = u"VARCHAR"
	//	qp[2].br[1].v = u"year"
	//	qp[2].br[2].v = u"VARCHAR"
	//===================================================================================================
	bool loaded = false;
	_tableName = table;

	SelectSql("pragma table_info(" + table + ")", "cid", vTableInfo);

	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)						// loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];
		UnicodeString _colName = q.br[1].v;  					//assign column name to var
		int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type
		q.br[1].t = q.br[found+1].v;                 	//assign the field type to the base record field type for later use.
		}
	if(c > 0)
		loaded = true;
	return(loaded);
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::GetDatabaseTables()
	{
	SelectSql(SQLITE_TABLE, "cid", vTables);

	size_t c = dbTablesResult.size();
	for(size_t x = 0; x < c; ++x)						//loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbTablesResult[x];
		UnicodeString _colName = q.br[1].v;  					//assign column name to var
		int found = GetPropFieldValue(q.br, _colName);	// find the index of the col def vector record containg the type
		q.br[1].t = q.br[found+1].v;                 	//assign the field type to the base record field type for later use.
		}
	}
//---------------------------------------------------------------------------
UnicodeString __fastcall TSQLite::PropertyType(std::vector<TBaseRecord>& r, UnicodeString name)
	{
	//===============================================================================================
	// get the property type from vector of field values
	// example of call to this function;
	// 				sz = SQLite1->PropertyType(SQLite1->dbQueryResult[1].br, "pfactor");
	//===============================================================================================

	int found;
	GetFieldValue(r, name, found);	//find the index into the vector containg the type value of the column name

	if (found == -1)
		return "";

	return r[found].t;
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords>& __fastcall TSQLite::FieldProps()
	{
	return dbPropertyResult;
	}
//---------------------------------------------------------------------------
std::vector<TDBRecords>& __fastcall TSQLite::FieldValues()
	{
	return dbQueryResult;
	}
//---------------------------------------------------------------------------
AnsiString __fastcall TSQLite::getDatabaseSource()
	{
	return _dbSource;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::setDatabaseSource(AnsiString value)
	{
	_dbSource = value;
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindType(UnicodeString ColumnName, UnicodeString &value)
	{
	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)							// 	loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];

		UnicodeString _colName = q.br[1].v;						//	assign column name to var

		if (_colName == ColumnName)          				//  compare vector element with ColumnName parameter
			{
			int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type
			value = q.br[found+1].v;                 		//assign the field type to the base record field type for later use.
			return true;
			}
		}

	return false;
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value)
	{
	return FindPropertyValue(ColumnName, value, 0);
	}
//---------------------------------------------------------------------------
bool __fastcall TSQLite::FindPropertyValue(UnicodeString ColumnName, UnicodeString &value, int _property)
	{
	size_t c = dbPropertyResult.size();
	for(size_t x = 0; x < c; ++x)							// 	loop by the value of the number of TBaseRecords in property type vector qp
		{
		TDBRecords &q = dbPropertyResult[x];

		UnicodeString _colName  = q.br[1].v;    			//	assign column name to var

		if (_colName == ColumnName)							//  compare vector element with ColumnName parameter
			{
			int found = GetPropFieldValue(q.br, _colName);	//find the index of the col def vector record containg the type

			switch (_property)
				{
				case pColtype:
					value = q.br[found+1].v;			//assign the field type to the base record field type for later use.
					break;
				case pNotNull:
					value = q.br[found+2].v;          	//assign the field type to the base record field type for later use.
					break;
				case pDflt_Value:
					value = q.br[found+3].v;          	//assign the field type to the base record field type for later use.
					break;
				case pPk:
					value = q.br[found+4].v;          	//assign the field type to the base record field type for later use.
					break;
				}

			return true;
			}
		}

	return false;
	}
//---------------------------------------------------------------------------
void __fastcall TSQLite::ClearParameters()
	{
	/*
	for(size_t i = 0; i < Params.size(); ++i)
		delete Params[i];
	Params.clear();
	*/
	}
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
int __fastcall TSQLite::GetLastAutoIncrement(UnicodeString table)
	{
	//  Get the last sequence AUTOINCREMENT number of a table for AUTOINCREMENT field if any.
	SelectSql("select seq from sqlite_sequence where name = " + QuotedStr(table), vRecords);

	if (!dbQueryResult.empty())
		return StrToInt(dbQueryResult[0].br[0].v);

	return -1;
	}
//---------------------------------------------------------------------------
__fastcall TSQLite::TSQLite(TComponent* Owner)
	: TComponent(Owner)
		{
		}
//---------------------------------------------------------------------------
namespace Tsqlitecomponent
{
	void __fastcall PACKAGE Register()
	{
		TComponentClass classes[1] = {__classid(TSQLite)};
		RegisterComponents(L"SQLiteTest", classes, 0);
	}
}
//---------------------------------------------------------------------------
.h

Code: Select all

//---------------------------------------------------------------------------

#ifndef TSqliteComponentH
#define TSqliteComponentH
//---------------------------------------------------------------------------
#include <System.SysUtils.hpp>
#include <System.Classes.hpp>
#include <windows.h>
#include <StrUtils.hpp>


#include <vector>
#include <algorithm>

#include "sqlite3.h"
//#include "sqlite3ext.h"


enum loadwhich {vRecords, vTableInfo, vTables};
enum pProperty {pColtype, pNotNull, pDflt_Value, pPk};

#define SQLITE_TABLE "SELECT * FROM sqlite_master ORDER BY type"

//---------------------------------------------------------------------------
struct TBaseRecord
	{
	//===================================================================================================
	// storage for each column returned by an select a statement
	// example:
	//		sql = "SELECT * FROM MAKE";  gets all columns from table make.
	//===================================================================================================
	String c; // column name
	String v; // value
	String t; // column type
	String l; // column length
	};
//---------------------------------------------------------------------------
struct TDBRecords
	{
	//===================================================================================================
	// vector of all record values returned from database sql query
	//
	//===================================================================================================
	String fieldName; 	// column name
	int id;
	std::vector<TBaseRecord> br;
	};
//---------------------------------------------------------------------------
class PACKAGE TSQLite : public TComponent
	{
	friend class TBaseRecord;
	friend class TDBRecords;
	friend class TSQLiteComboBox;
	friend class TSQLiteTreeView;
	friend class TSQLiteAgent;

	private:
		sqlite3 *_db;

		AnsiString _dbSource;
		std::vector<TDBRecords> dbQueryResult;
		std::vector<TDBRecords> dbPropertyResult;
		std::vector<TDBRecords> dbTablesResult;

		AnsiString __fastcall getDatabaseSource();
		void __fastcall setDatabaseSource(AnsiString value);

		UnicodeString _tableName;


	protected:

	public:
		__fastcall TSQLite(TComponent* Owner);
		__fastcall ~TSQLite();

		int __fastcall GetLastAutoIncrement(UnicodeString table);

		std::vector<TBaseRecord>& __fastcall GetValuesByrecordId(int id);
		std::vector<TDBRecords>& __fastcall FieldProps();
		std::vector<TDBRecords>& __fastcall FieldValues();

		void __fastcall Open();
		void __fastcall Open16();
		void __fastcall OpenV2(int flags, AnsiString zVfs);
		void __fastcall Close();
		void __fastcall CloseV2();

		bool __fastcall TableInfo(UnicodeString table);

		void __fastcall SelectSql(UnicodeString sql, UnicodeString _id, int _get);
		void __fastcall SelectSql(UnicodeString sql, int _get);
		void __fastcall Execute(AnsiString sql);

		UnicodeString __fastcall PropertyType(std::vector<TBaseRecord>& r, UnicodeString name);
		UnicodeString __fastcall GetFieldValue(std::vector<TBaseRecord>& r, UnicodeString col_name, int &_foundIndex);
		int __fastcall GetPropFieldValue(std::vector<TBaseRecord>& r, UnicodeString col_name);
		UnicodeString __fastcall ValueType(UnicodeString colName, std::vector<TBaseRecord>& r);
		UnicodeString __fastcall GetValuesByrecordId(int id, UnicodeString col_name);

		int __fastcall Prepair(UnicodeString sql);
		void __fastcall AddParameter(UnicodeString ColumnName, UnicodeString Value);
		bool __fastcall FindType(UnicodeString _column_name, UnicodeString &value);

		bool __fastcall FindPropertyValue(UnicodeString ColumnName, UnicodeString &value, int _property);
		bool __fastcall FindPropertyValue(UnicodeString ColumnName, UnicodeString &value);
		void __fastcall ClearParameters();
		void __fastcall GetDatabaseTables();

	__published:
		__property AnsiString DBPath = {read=getDatabaseSource, write=setDatabaseSource};
	};
//---------------------------------------------------------------------------
#endif


Form code

Code: Select all

//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma link "TSQLiteComponent"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
if(OpenDialog1->Execute())
	{
        q->DBPath = OpenDialog1->FileName;
    }
}
//---------------------------------------------------------------------------
errors

Code: Select all

ilink32 command line
  c:\program files (x86)\embarcadero\studio\20.0\bin\ilink32.exe -G8 -L.\Win32\Debug;"E:\Dev-Berlin\SQLiteComponents\Remy\bpl";
  "E:\Dev-Berlin\SQLiteComponents\Remy\Win32\Debug";"c:\program files (x86)\embarcadero\studio\20.0\lib\Win32\debug";..\SQLiteComponents\Remy;
  C:\Users\Len\Documents\Embarcadero\Studio\Projects;"C:\Dev-Berlin\TestPackage";"E:\Dev-Berlin\bpi-lib";"I:\Berlin_10 bpl_lib";"c:\program files 
  (x86)\embarcadero\studio\20.0\lib\win32\release";"c:\program files (x86)\embarcadero\studio\20.0\lib\win32\release\psdk";
  C:\Users\Public\Documents\Embarcadero\Studio\20.0\DCP -j.\Win32\Debug;"E:\Dev-Berlin\SQLiteComponents\Remy\bpl";
  "E:\Dev-Berlin\SQLiteComponents\Remy\Win32\Debug";"c:\program files (x86)\embarcadero\studio\20.0\lib\Win32\debug";..\SQLiteComponents\Remy;
  C:\Users\Len\Documents\Embarcadero\Studio\Projects;"C:\Dev-Berlin\TestPackage";"E:\Dev-Berlin\bpi-lib";"I:\Berlin_10 bpl_lib";"c:\program files 
  (x86)\embarcadero\studio\20.0\lib\win32\release";"c:\program files (x86)\embarcadero\studio\20.0\lib\win32\release\psdk";
  C:\Users\Public\Documents\Embarcadero\Studio\20.0\DCP -lC:\Users\Public\Documents\Embarcadero\Studio\20.0\DCP -v -Gi 
  -GA"C:\Users\User\AppData\Local\Temp\vfs358C.tmp"="E:\Dev-Berlin\TestPackage\Unit1.dfm" -aa -V5.0 -GBTestProj1 -Tpp c0pkg32w rtl.bpi memmgr.lib 
  sysinit.obj .\Win32\Debug\TestProj1.obj .\Win32\Debug\Unit1.obj , C:\Users\Public\Documents\Embarcadero\Studio\20.0\BPL\TestProj1.bpl , 
  C:\Users\Public\Documents\Embarcadero\Studio\20.0\BPL\TestProj1.map , import32.lib cp32mt.lib , , TestProj1.res 
[ilink32 Warning] Warning: Compiler mismatch. Module 'E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ' built with bcc32c compiler; expected the bcc32 compiler because of 'E:\DEV-BERLIN\TESTPACKAGE\WIN32\DEBUG\TESTPROJ1.OBJ'.
[ilink32 Warning] Warning: Compiler mismatch. Module 'C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\20.0\LIB\WIN32\DEBUG\RTLE.LIB|dstring' built with bcc32c compiler; expected the bcc32 compiler because of 'E:\DEV-BERLIN\TESTPACKAGE\WIN32\DEBUG\TESTPROJ1.OBJ'.
[ilink32 Warning] Warning: Compiler mismatch. Module 'C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\20.0\LIB\WIN32\DEBUG\RTLE.LIB|syssupp' built with bcc32c compiler; expected the bcc32 compiler because of 'E:\DEV-BERLIN\TESTPACKAGE\WIN32\DEBUG\TESTPROJ1.OBJ'.
[ilink32 Warning] Warning: Compiler mismatch. Module 'C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\20.0\LIB\WIN32\DEBUG\RTLE.LIB|ustring' built with bcc32c compiler; expected the bcc32 compiler because of 'E:\DEV-BERLIN\TESTPACKAGE\WIN32\DEBUG\TESTPROJ1.OBJ'.
[ilink32 Error] Error: Unresolved external '___seh_personality_v0' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_Unwind_SjLj_Register' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '__cxxabiv1::__class_type_info::' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '___cxa_pure_virtual' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '__cxxabiv1::__si_class_type_info::' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '__Unwind_SjLj_Unregister' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '___cxa_begin_catch' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '___cpp_terminate' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '__Unwind_Resume' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '___cxa_end_catch' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external 'std::_Xlength_error(const char *)' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external 'std::_Xbad_alloc()' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external 'std::ios_base::Init::{1173}...' referenced from C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\20.0\LIB\WIN32\DEBUG\RTLE.LIB|ustring
[ilink32 Error] Error: Unresolved external 'std::_Winit::{1173}...' referenced from C:\PROGRAM FILES (X86)\EMBARCADERO\STUDIO\20.0\LIB\WIN32\DEBUG\RTLE.LIB|ustring
[ilink32 Error] Error: Unresolved external '___cxa_rethrow' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_open' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '___cxa_throw2' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_open16' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_open_v2' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_close' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_close_v2' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_exec' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unresolved external '_sqlite3_free' referenced from E:\DEV-BERLIN\SQLITECOMPONENTS\REMY\WIN32\DEBUG\TSQLITECOMPONENT.OBJ
[ilink32 Error] Error: Unable to perform link
Failed
Elapsed time: 00:00:02.6
Post Reply