Пример #1
0
void CompatibilityManager::migrateAccounts(const shared_ptr<IPortalDatabase> &database)
{
	shared_ptr<IDbConnection> globalConnection = Engine::instance()->createSystemConnection();

	DataTable result;
	String sql = _S("select * from os_accounts");
	
	database->execute(sql,result);

	for(uint32 r=0;r<result.rows();r++)
	{
		String id = result.get(r,_S("id"));

		shared_ptr<DataAccount> dataAccount(OS_NEW DataAccount());

		dataAccount->read(result[r]);

		dataAccount->description = _S("Imported from portal '") + database->getPortal()->getName();
		
		String sql = String::format(_S("select count(*) from os_accounts where id='%S'").c_str(), id.c_str());
		int nRecordExists = globalConnection->value_of(sql);
		bool alreadyExists = (nRecordExists>0); 

		DbSqlValues values;
		dataAccount->write(values);
		if(alreadyExists)
			globalConnection->executeStatement(globalConnection->prepare_update(DBTABLES::ACCOUNTS_TABLE, values, DBTABLES::ACCOUNTS::ID, Convert::toSQL(dataAccount->id)), values);
		else
		
			globalConnection->executeStatement(globalConnection->prepare_insert(DBTABLES::ACCOUNTS_TABLE, values), values);
	}
}
Пример #2
0
DataItem IDbConnection::queryValue(const String &sql)
{
	DataItem value;

	DataTable result;
	if(query(sql, result))
		if(result.rows() > 0 && result.columns() > 0)
			value = *result[0][0];			
	return value;
}
Пример #3
0
uint32 IDbConnection::value_of(const String &sql) // TOCLEAN, rimpiazzare con la queryValue
{
	DataTable result;
	if(query(sql, result) == false)
		return false;

	uint32 value = 0;
	if(result.rows() > 0 && result.columns() > 0)
		value = *result[0][0];

	return value;
}
Пример #4
0
void CompatibilityManager::resigner(const shared_ptr<IPortalDatabase> &database, shared_ptr<IdeSession> session)
{
	shared_ptr<ObjectsUser> user = session->getUser(database);
	if(user != nullptr)
	{
		Buffer signature = user->signature;
		if( (signature.getSize() == 1) && (signature.getAt(0) == 0) )
		{
			// Need re-sign.
			DataTable result;
			String sql = String::format(_S("select id,entity_author,author from os_entries where author='%S' union select id,entity_author,author from os_entries where entity_author='%S'").c_str(),user->id->toUTF16().c_str(),user->id->toUTF16().c_str());
			database->execute(sql,result);

			for(uint32 r=0;r<result.rows();r++)
			{
				String id = result.get(r,_S("id"));
				String entityAuthor = result.get(r,_S("entity_author"));
				String author = result.get(r,_S("author"));

				shared_ptr<ObjectsIObject> object = database->getPortal()->getObject(database, id.to_ascii());
				if(object != nullptr)
				{
					LanguageResult acceptable = object->acceptable(database);
					if(acceptable.empty())
					{
						if( (entityAuthor == user->id->toUTF16()) && (author == user->id->toUTF16()) )
						{
							shared_ptr<ObjectsIRevisionable> revisionable = objects_revisionable_cast(object);			
							if(revisionable != nullptr)
							{
								bool done = revisionable->signEntity(session->getPrivateKey(), database->getPortal()->getPortalID());
								OS_ASSERT(done);
							}
						}

						if(author == user->id->toUTF16())
						{
							bool done = object->sign(session->getPrivateKey(), database->getPortal()->getPortalID());							
							OS_ASSERT(done);
						}

						LanguageResult result = object->store(database);
						OS_ASSERT(result.empty());						
					}
				}
			}
		}
	}
}
Пример #5
0
shared_ptr<EntitiesEntities> EntitiesEntity::getChilds(const shared_ptr<IPortalDatabase> &database, const ObjectsTypes &types, const RangeUint32 &range, shared_ptr<DbSqlSelect> select) const
{
	OS_ASSERT(select != nullptr);
	OS_ASSERT(select->count == false);

	OS_LOCK(m_cs);

	String sql;
	// Genera l'sql di caricamento dei figli
	_getSql(database, types, range, false, select, sql);

	String childsKey = getChildsKey(types);

	shared_ptr<EntitiesEntities> childs = m_childs.get(childsKey);
	// Controlla se i figli della tipologia specificata sono gi stati caricati in precedenza
	if(childs != nullptr)
	{
		if(childs->getRange() == range && childs->getSql() == sql)
			return childs;	// Se il range in cui sono stati caricati i figli e l'sql di estrazione corrispondono non serve effettuare nuovamente il caricamento...

		// Nota: se il range richiesto non coincide con quello attuale o l'sql  differente bisogna ricaricare i figli
		// Anche se il range attuale comprendesse quello richiesto bisogna comunque ricaricare i figli altrimenti dall'esterno,
		// una volta richiesto un range, scorrendo i figli non si avrebbe la certezza che siano nel range richiesto (a meno di complicare i vari giri)

		m_childs.remove(childsKey);
	}

	// Inizializza la lista dei figli prima di aprire il database (la connessione potrebbe fallire, ma la lista deve essere comunque creata)
	childs.reset(OS_NEW EntitiesEntities(const_cast <EntitiesEntity *>(this)->get_this_ptr(), sql));
	m_childs.push_back(childsKey, childs);

	DataTable result;
	database->execute(sql, result);
	for(uint32 i = 0; i < result.rows(); i++)
	{
		String child_id = result.get(i, DBTABLES::ENTITY);
		childs->push_back(child_id.to_ascii());
	}

	return childs;
}
Пример #6
0
bool IExtensionsExtension::isExtensionRegistered(shared_ptr<Portal> portal, shared_ptr<IPortalDatabase> db, Version &version) const
{
	OS_ASSERT(portal != nullptr);

	OS_EXCEPT_IF(db == nullptr, "Invalid database");

	shared_ptr<DbSqlSelect> select(OS_NEW DbSqlSelect(DBTABLES::EXTENSIONS_TABLE));
	select->fields.add(DbSqlField(DBTABLES::EXTENSIONS::VERSION));
	select->where.add(DBTABLES::EXTENSIONS::ID, Convert::toSQL(getID().toUTF16()));
	select->limit.setCount(1);

	DataTable result;
	if(db->execute(select, result) == false)
		return false;

	if(result.rows() == 0)
		return false;

	version.fromString(static_cast<String>(*result[0][0]).to_ascii());
	return true;
}
Пример #7
0
bool P2pMachine::load(const String &id)
{
	try
	{
		shared_ptr<IDbConnection> connection = Engine::instance()->createSystemConnection();
		
		shared_ptr<DbSqlSelect> select(OS_NEW DbSqlSelect(_S("os_machines")));
		select->where.add(_S("id"), Convert::toSQL(id));
		select->limit.setCount(1);

		DataTable result;
		connection->query(select, result);

		if(result.rows() == 1)
		{
			DataTableRow row = result[0];

			DbValue<String> id;
			id.read(row, _S("id"));
			if(m_id.fromHex(id->to_ascii()) == false)
			{
				OS_ASSERTFALSE();
				return false;
			}

			DbValue<Buffer> public_key;
			public_key.read(row, _S("public_key"));
			m_publicKey = public_key;

			return true;
		}
	}
	catch(std::exception &e)
	{
		OS_LOG_ERROR(e.what());
	}

	return false;
}
Пример #8
0
String Connection::preAnalyze(const String &sql)
{
	static boost::recursive_mutex cs;
	OS_LOCK(cs);

	// Per vedere le sql nel charts:
	// RealtimeStatsManager::signal(sql, 1, RealtimeStatsCounter::ctAbsolute, _S("status"));

	// Da notare che vengono archiviate nella os_monitor solo le query analizzate dalla "explain".
	// Una "insert", non usando indici, non viene catalogata, a meno che non abbia sotto-query.

	if(sql.find(_S("explain query plan ")) != String::npos)
		return _S("");

	if(sql.find(_S("os_monitor")) != String::npos)
		return _S("");

	static shared_ptr<Connection> connectionAnalyze = nullptr;
	if(connectionAnalyze == nullptr)
	{
		shared_ptr<Driver> driver = boost::dynamic_pointer_cast<Driver>(getDriver());
		String path = driver->getDatabasePath(_S("monitor.db"));
		if(FileSystem::instance()->exists(path) == false)
		{
			// Crea il database se non esiste
			File file;
			String msg = _S("Cannot create file '") + path + _S("'");
			OS_EXCEPT_IF(file.open(path, File::ofWrite) == false, msg.to_ascii());
		}

		connectionAnalyze.reset(OS_NEW Connection(path, getDriver()->createOptions(), getDriver()));

		int32 res = _tsqlite3_open(path.c_str(), &connectionAnalyze->m_connection);
		OS_EXCEPT_IF(res != SQLITE_OK, sqlite_last_error(connectionAnalyze->m_connection, res));

		// Creazione tabella
		String sqlCreate = _S("CREATE TABLE IF NOT EXISTS os_monitor (filename text,sql text,thread integer,conn integer,trans integer, qorder integer,qfrom integer,detail text,indexUsed text)");
		doExecute(connectionAnalyze->m_connection, sqlCreate);
	}

	// I valori dei campi li setto a ?, per poter fare delle distinct sui risultati
	String keySql = sql;
	keySql.trim();
	keySql = regex_replace(keySql, RegexManager::instance()->getRegex(_S("'(.*?)'")), _S("<s>")); // Valori dei campi
	keySql = regex_replace(keySql, RegexManager::instance()->getRegex(_S("[-+]?[0-9]*\\.?[0-9]+")), _S("<n>")); // Numeri
	keySql = keySql.replace_all(_S("\n"),_S(""));
	keySql = keySql.replace_all(_S("\r"),_S(""));
	keySql = keySql.replace_all(_S("\t"),_S(""));
	keySql = keySql.replace_all(_S("'"),_S("")); // Futile, per evitare errori nella insert nella os_monitor
	for(;;) // Comprimo gli spazi
	{
		String x = keySql;
		keySql = keySql.replace_all(_S("  "),_S(" "));
		if(x == keySql)
			break;
	}

	uint32 conn = uint32(reinterpret_cast<uint64>(this));
	boost::any threadID = PlatformManager::instance()->getCurrentThreadID();
	// Tenta un cast a uint32
	uint32 *thread = boost::any_cast<uint32>(&threadID);
	int32 trans = m_transactionId;

	DataTable result;
	doQuery(m_connection, _S("explain query plan ") + sql,result);

	for(uint32 r=0;r<result.rows();r++)
	{
		int32 order = *result.get(r,_S("order"));
		int32 from = *result.get(r,_S("from"));
		String detail = *result.get(r,_S("detail"));

		String indexUsed;
		String::size_type posWithIndex = detail.find(_S("WITH INDEX"));
		if(posWithIndex != String::npos)
		{
			indexUsed = detail.substr(posWithIndex+10);
			indexUsed = indexUsed.replace_all(_S("ORDER BY"),String::EMPTY);
			indexUsed.trim();
		}

		String sqlInsert = String::format(_S("insert into os_monitor values ('%S','%S',%u,%u,%u,%d,%d,'%S','%S')").c_str(), m_filename.c_str(), keySql.c_str(), conn, thread != nullptr ? *thread : 0, trans, order, from, detail.c_str(), indexUsed.c_str());
		doExecute(connectionAnalyze->m_connection, sqlInsert);
	}

	String trace = String::format(_S("Sqlite monitor: sql='%S',conn=%u,thread=%u,trans=%u\n").c_str(), sql.c_str(), conn, thread != nullptr ? *thread : 0, trans);
	//OS_TRACE(trace);

	//RealtimeStatsManager::signal(_S("Sqlite ") + keySql.mid(0,6), 1, RealtimeStatsCounter::ctRelative, _S("items"));
	return keySql;
}
Пример #9
0
void CompatibilityManager::renameIDS(const shared_ptr<IPortalDatabase> &database)
{
	/*
		if(id == 2) // Reputation
			newID = database->getUserReputationID(
		else if(id == 7) // Avatar
		else if(id == 14) // Vote
		else if(id == 17) // PollVote
	}
	*/

	// Reputations
	{
		DataTable result;
		String sql = _S("select id, author, reference from os_reputations");
		database->execute(sql,result);

		for(uint32 r=0;r<result.rows();r++)
		{
			String id = result.get(r,_S("id"));
			String author = result.get(r,_S("author"));
			String reference = result.get(r,_S("reference"));

			ObjectID newID = database->getUserReputationID(author.to_ascii(), reference.to_ascii());

			String sql = _S("update os_reputations set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
			sql = _S("update os_entries set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
		}
	}

	// Avatars
	{
		DataTable result;
		String sql = _S("select id, author from os_avatars");
		database->execute(sql,result);

		for(uint32 r=0;r<result.rows();r++)
		{
			String id = result.get(r,_S("id"));
			String author = result.get(r,_S("author"));
			
			ObjectID newID = database->getUserAvatarID(author.to_ascii());

			String sql = _S("update os_avatars set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
			sql = _S("update os_entries set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
		}
	}

	// Vote
	{
		DataTable result;
		String sql = _S("select id, author, reference from os_votes");
		database->execute(sql,result);

		for(uint32 r=0;r<result.rows();r++)
		{
			String id = result.get(r,_S("id"));
			String author = result.get(r,_S("author"));
			String reference = result.get(r,_S("reference"));
			
			ObjectID newID = database->getUserVoteID(author.to_ascii(), reference.to_ascii());

			String sql = _S("update os_votes set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
			sql = _S("update os_entries set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
		}
	}

	// PollVote
	{
		DataTable result;
		String sql = _S("select id, author, reference from os_polls_votes");
		database->execute(sql,result);

		for(uint32 r=0;r<result.rows();r++)
		{
			String id = result.get(r,_S("id"));
			String author = result.get(r,_S("author"));
			String reference = result.get(r,_S("reference"));
			
			ObjectID newID = database->getUserPollVoteID(author.to_ascii(), reference.to_ascii());

			String sql = _S("update os_polls_votes set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
			sql = _S("update os_entries set id=") + Convert::toSQL(newID) + _S(" where id=") + Convert::toSQL(id);
			database->execute(sql);
		}
	}
}
Пример #10
0
void IdeTableQuery::onPreRender()
{
	ControlBase::onPreRender();
	
	shared_ptr<XMLDocument> document = getDocument();
	shared_ptr<XMLNode> node_root = document->create(_S("table_query"));

	DataTable result;
	if(getPage()->getDatabase()->execute(m_sql,result))
	{
		shared_ptr<XMLNode> node_header = node_root->addChild(_S("header"));

		for(uint32 c = 0; c < result.columns(); c++)
		{
			String columnTitle = getColumnTitle(c);
			if(columnTitle.empty())
				columnTitle = result.getColumnName(c);

			shared_ptr<XMLNode> node_column = node_header->addChild(_S("column"));

			node_column->setAttributeString(_S("name"), columnTitle);

			switch(getColumnType(c))
			{
			case IdeTableQuery::ctString:
				{
					node_column->setAttributeString(_S("type"), _S("string"));
				} break;
			case IdeTableQuery::ctScore:
				{
					node_column->setAttributeString(_S("type"), _S("score"));
				} break;
			case IdeTableQuery::ctEntityID:
				{
					node_column->setAttributeString(_S("type"), _S("entity-id"));
				} break;
			case IdeTableQuery::ctObjectID:
				{
					node_column->setAttributeString(_S("type"), _S("object-id"));
				} break;
			case IdeTableQuery::ctUserID:
				{
					node_column->setAttributeString(_S("type"), _S("user-id"));
				} break;
			case IdeTableQuery::ctShortDateTime:
				{
					node_column->setAttributeString(_S("type"), _S("short-datetime"));
				} break;
			case IdeTableQuery::ctLongDateTime:
				{
					node_column->setAttributeString(_S("type"), _S("long-datetime"));
				} break;
			}
		}

		shared_ptr<XMLNode> node_data = node_root->addChild(_S("data"));

		for(uint32 r=0;r<result.rows();r++)
		{
			shared_ptr<XMLNode> node_data_row = node_data->addChild(_S("row"));

			for(uint32 c=0;c<result.columns();c++)
			{
				shared_ptr<XMLNode> node_data_row_item = node_data_row->addChild(_S("item"));

				String value = result.get(r,c);

				switch(getColumnType(c))
				{
				case IdeTableQuery::ctScore:
					{
						node_data_row_item->setAttributeString(_S("value"), String::format(_S("%1.1f").c_str(), double(result.get(r,c))));
					} break;
				case IdeTableQuery::ctEntityID:
					{
						// Sbagliata
						shared_ptr<XMLPortalExporter> exporter(OS_NEW XMLPortalExporter(node_data_row_item, getPage(), XMLPortalExporter::emLite));
						shared_ptr<ObjectsIObject> object = getPage()->getObject(value.to_ascii());
						if(object != nullptr)
						{
							object->exportXML(exporter);
						}
					} break;
				case IdeTableQuery::ctObjectID:
					{
						shared_ptr<XMLPortalExporter> exporter(OS_NEW XMLPortalExporter(node_data_row_item, getPage(), XMLPortalExporter::emLite));
						shared_ptr<ObjectsIObject> object = getPage()->getObject(value.to_ascii());
						if(object != nullptr)
						{
							object->exportXML(exporter);
						}
					} break;
				case IdeTableQuery::ctUserID:
					{
						shared_ptr<XMLPortalExporter> exporter(OS_NEW XMLPortalExporter(node_data_row_item, getPage(), XMLPortalExporter::emLite));
						shared_ptr<ObjectsIObject> object = getPage()->getObject(value.to_ascii());
						if(object != nullptr)
						{
							object->exportXML(exporter);
						}
					} break;
				case IdeTableQuery::ctShortDateTime:
				case IdeTableQuery::ctLongDateTime:
					{
						DateTime dt;
						dt.fromString(value);
						node_data_row_item->setAttributeDateTime(_S("value"), dt);
					} break;
				default:
					{
						node_data_row_item->setAttributeString(_S("value"), value);
					} break;
				}
			}
		}
	}
}
Пример #11
0
void Forum::computeStatistics(shared_ptr<IPortalDatabase> db, shared_ptr<ObjectsIObject> object)
{
	ComponentBase::computeStatistics(db, object);

	shared_ptr<ObjectsSection> section = objects_section_cast(object);

	shared_ptr<ForumStats> stats(OS_NEW ForumStats());

	stats->reference = section->getEntityID().toUTF16();
	stats->topics = 0;
	stats->posts = 0;

	uint32 directTopics=0;
	uint32 directPosts=0;
	// Calcolo le statistiche sui topics figli
	{
		String sql = String::format(_S("select count(*), sum(os_discussions_stats.posts) from os_discussions_stats, os_snapshot_objects where \
								    os_snapshot_objects.parent = '%S' \
									and os_snapshot_objects.type in (%d,%d) \
									and os_snapshot_objects.visible = 1 \
									and os_discussions_stats.reference = os_snapshot_objects.entity \
									and os_discussions_stats.parent = '%S'").c_str(),
									section->getEntityID().toUTF16().c_str(),
									portalObjectTypeText,
									portalObjectTypePoll,
									section->getEntityID().toUTF16().c_str()
									);

		DataTable table;
		db->execute(sql, table);
		directTopics = *table[0][0];
		directPosts = *table[0][1];
	}

	uint32 indirectTopics=0;
	uint32 indirectPosts=0;
	// Calcolo le statistiche sui forums figli
	{
		String sql = String::format(String(_S("\
									select sum(") + OS_FORUMS_FORUM_STATS_TABLE + _S(".topics), sum(") + OS_FORUMS_FORUM_STATS_TABLE + _S(".posts) \
									from ") + OS_FORUMS_FORUM_STATS_TABLE + _S(",os_snapshot_objects,os_sections \
									where \
								    os_snapshot_objects.entity = ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".reference and \
									os_snapshot_objects.current = os_sections.id and \
									os_sections.component = '%S' and \
									os_snapshot_objects.parent = '%S' and \
									os_snapshot_objects.visible = 1")).c_str(),
									getID().toUTF16().c_str(),
									section->getEntityID().toUTF16().c_str());

		DataTable table;
		db->execute(sql, table);
		indirectTopics = *table[0][0];
		indirectPosts = *table[0][1];
	}
	stats->reference = section->getEntityID().toUTF16();
	stats->topics = directTopics + indirectTopics;
	stats->posts = directPosts + indirectPosts;

	// Calcolo le statistiche riferite ai topic figli
	{
		String sql = String::format(_S("\
			select os_discussions_stats.reference, os_discussions_stats.last_entry, os_discussions_stats.last_entry_date \
			from \
			os_snapshot_objects, \
			os_discussions_stats \
			where \
			os_snapshot_objects.entity = os_discussions_stats.reference and \
			os_snapshot_objects.parent = '%S' and \
			os_snapshot_objects.type in (%d,%d) and \
			os_snapshot_objects.visible = 1 \
			order by os_discussions_stats.last_entry_date desc \
			limit 1").c_str(),
		section->getEntityID().toUTF16().c_str(),
		portalObjectTypeText,
		portalObjectTypePoll);

		DataTable table;
		db->execute(sql, table);
		if(table.rows()>0)
		{
			stats->last_topic = *table[0][0];
			stats->last_message = *table[0][1];
			stats->last_message_date = *table[0][2];
		}
	}

	// Calcolo le statistiche riferite ai forums figli
	{
		String sql = String::format(String(_S("\
			select ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".last_topic, ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".last_message, ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".last_message_date \
			from \
			os_snapshot_objects, \
			") + OS_FORUMS_FORUM_STATS_TABLE + _S(", \
			os_sections \
			where \
			os_snapshot_objects.entity = ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".reference and \
			os_snapshot_objects.current = os_sections.id and \
			os_sections.component = '%S' and \
			os_snapshot_objects.parent = '%S' and \
			os_snapshot_objects.visible = 1 \
			order by ") + OS_FORUMS_FORUM_STATS_TABLE + _S(".last_message_date desc \
			limit 1")).c_str(),
		getID().toUTF16().c_str(),
		section->getEntityID().toUTF16().c_str());

		DataTable table;
		db->execute(sql, table);
		if(table.rows()>0)
		{
			DateTime last_message_date = static_cast<String>(*table[0][2]);
			if( (stats->last_message_date->isNull()) || (last_message_date > stats->last_message_date) )
			{
				stats->last_topic = *table[0][0];
				stats->last_message = *table[0][1];
				stats->last_message_date = *table[0][2];
			}
		}
	}

	db->updateRecord(stats);
}
Пример #12
0
void SearchResultsDatabase::executeQuery(shared_ptr<IPortalDatabase> database, shared_ptr<Portal> portal, shared_ptr<SearchQuery> query, const StringMap& objectsMap)
{
	clear();

	shared_ptr<DbSqlSelect> select(new DbSqlSelect(DBTABLES::SNAPSHOT_OBJECTS_TABLE));
	select->fields.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE));
	// Se  il primo step di un groupMode, ho bisogno di estrarre anche il padre.
	if(query->getGroupMode() && (objectsMap.empty()))
		select->fields.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::PARENT, DBTABLES::SNAPSHOT_OBJECTS_TABLE));
	
	// Solo se non  specificata gi una lista di oggetti.
	// Le where si riferiscono agli oggetti singoli (ex. post), non al loro oggetto da visualizzare.
	// Quindi non  necessario specificarle nel secondo giro.
	if(objectsMap.empty())
	{
		// current != ""
		select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::CURRENT, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(String::EMPTY), DbSqlCondition::cfDifferent | DbSqlCondition::cfAnd);

		// Controlla se  stata specificata una data di creazione minima
		const DateTime &fromSubmitDate = query->convertSearchDateTime(query->getFromSubmitDateType(),query->getFromSubmitDateSpecific());
		if(fromSubmitDate.isValid())
		{
			// submit_date >= fromSubmitDate
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(fromSubmitDate), DbSqlCondition::cfMajor | DbSqlCondition::cfEqual | DbSqlCondition::cfAnd);
		}

		// Controlla se  stata specificata una data di creazione massima
		const DateTime &toSubmitDate = query->convertSearchDateTime(query->getToSubmitDateType(),query->getToSubmitDateSpecific());
		if(toSubmitDate.isValid())
		{
			// submit_date <= toSubmitDate
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(toSubmitDate), DbSqlCondition::cfMinor | DbSqlCondition::cfEqual | DbSqlCondition::cfAnd);
		}

		// Controlla se  stata specificata una data di inserimento minima
		const DateTime &fromInsertDate = query->convertSearchDateTime(query->getFromInsertDateType(),query->getFromInsertDateSpecific());
		if(fromInsertDate.isValid())
		{
			// insert_date >= fromInsertDate
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::INSERT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(fromInsertDate), DbSqlCondition::cfMajor | DbSqlCondition::cfEqual | DbSqlCondition::cfAnd);
		}

		// Controlla se  stata specificata una data di creazione massima
		const DateTime &toInsertDate = query->convertSearchDateTime(query->getToInsertDateType(),query->getToInsertDateSpecific());
		if(toInsertDate.isValid())
		{
			// insert_date <= toInsertDate
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::INSERT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(toInsertDate), DbSqlCondition::cfMinor | DbSqlCondition::cfEqual | DbSqlCondition::cfAnd);
		}

		// Non mostrare le entit virtuali. Dato che le entit virtuali hanno insertDate==null,
		select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::INSERT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(DateTime::EMPTY), DbSqlCondition::cfDifferent | DbSqlCondition::cfAnd);

		// Se non deve mostrare gli oggetti cancellati forza la visibilit ad 1
		if(query->getShowDeleted() == false)
			// visible == 1
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::VISIBLE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(true));

		StringList types;
		for(SearchQuery::Options::const_iterator i = query->getOptions().begin(); i != query->getOptions().end(); ++i)
		{
			shared_ptr<ISearchOptions> options = i->second;
			if(options->getActive())
			{
				types.push_back(Convert::toString(options->getType()));
			}
		}

		if(types.empty() == false)
			// type in (...)
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::TYPE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), types);

		// Ricerca in determinati padri
		StringList parentsList;
		query->computeParentsList(database, portal, parentsList);
		// Ci metto gli apici...
		for(StringList::iterator i = parentsList.begin(); i != parentsList.end(); ++i)
		{
			*i = _S("'") + String(*i) + _S("'");
		}
		if(!parentsList.empty())
		{
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::PARENT, DBTABLES::SNAPSHOT_OBJECTS_TABLE), parentsList);
		}

		// 0.14 RC3
		if(query->getText().substr(0,17) == _S("title-start-with:"))
		{
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::TITLE), Convert::toSQL(query->getText().substr(17) + _S("%")), DbSqlCondition::cfLike | DbSqlCondition::cfAnd);
		}

		// 0.14 RC3
		if(query->getText().substr(0,17) == _S("title-start-with:"))
		{
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::TITLE), query->getText().substr(17) + _S("%"), DbSqlCondition::cfLike | DbSqlCondition::cfAnd);
		}

		// 0.12
		if( (query->getByUser().empty() == false) && (query->getByUser() != _S("*")) )
		{
			String user = query->getByUser();
			
			// MySelf test
			if(user == _S("myself"))
			{
				// VERYURGENTRAZOR: Commentata perchè ho piallato il loggedUser come parametro... rivalutare la cosa
				/*
				if( (loggedUser != nullptr) && loggedUser->isLogged() && (loggedUser->getGuestMode() == false))
				{
					user = loggedUser->getUser()->id->toUTF16();
				}
				else
				{
					user == String::EMPTY;
				}
				*/
				user == String::EMPTY;
			}
			else
			{
				// VERYURGENT, un test migliore per verificare se è un ID?
				// VERYURGENT, l'sql potrebbe essere Sqlite-specifica.
				// Fatto meglio, dovrei avere un'altro combo "localizza per" "nick/id"
				// Inoltre qui ci sarebbe da supportare una ricerca "non exact-match" per farlo stile Invision.
				if(user.length() != 48)
				{
					algorithms::to_upper(user);
					String sql = String::format(_S("select rs.id from os_snapshot_users ts, os_users tu where ts.id=tu.id and upper(tu.name) = %S").c_str(), Convert::toSQL(user).c_str());
					DataTable result;
					if(database->execute(sql, result))
					{
						if(result.rows() > 0 && result.columns() > 0)
							user = static_cast<String>(*result[0][0]);
					}
				}
			}

			// Come autore della primaria
			select->tables.add(DbSqlTable(DBTABLES::ENTRIES_TABLE));
			// Crea la join
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField(DBTABLES::ENTRIES::ID, DBTABLES::ENTRIES_TABLE));
			select->where.add(DbSqlField(DBTABLES::ENTRIES::AUTHOR, DBTABLES::ENTRIES_TABLE), Convert::toSQL(user));

			// Come editore dell'oggetto
			// where DBTABLES::SNAPSHOT_OBJECTS::REFERENCE in (select id from os_entries where revision= getByUser();
		}
	}
	else
	{
		// Se objectsList  valorizzata, allora  il secondo passo di una ricerca in groupMode, gli passo l'elenco oggetti.

		StringList objectsList;
		for(StringMap::const_iterator i = objectsMap.begin(); i != objectsMap.end(); ++i)
		{
			objectsList.push_back(_S("'") + i->first + _S("'"));
		}
		//select->where.add(String(DBTABLES::SNAPSHOT_OBJECTS_TABLE) + _S(".") + DBTABLES::SNAPSHOT_OBJECTS::REFERENCE, objectsList);
		select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), objectsList);

	}

	// Se  il primo passaggio di una groupMode, l'ordinamento  inutile.
	// 0.12 RC5, tolto, con un limite nel primo giro di group-mode, devono essere ordinati.
	//if( (!query->getGroupMode()) || (!objectsMap.empty()) )
	{
		DbSqlField::Order order = DbSqlField::foNone;
		switch(query->getOrderDirection())
		{
		case searchOrderDirectionDescendent:	order = DbSqlField::foDesc;
												break;

		case searchOrderDirectionAscendent:		order = DbSqlField::foAsc;
												break;

		default:			OS_ASSERTFALSE();
							break;
		}

		SearchOrderMode orderMode = query->getOrderMode();

		// 0.12 RC5, da testare
		// Se è il primo passaggio di una group-mode, l'ordinamento "omLastObject" deve essere un "omSubmitDate".
		if( (query->getGroupMode()) && (objectsMap.empty()) )
		{
			if(orderMode == searchOrderModeLastObject)
				orderMode = searchOrderModeSubmitDate;
			else if(orderMode == searchOrderModeVotesTotal)
				orderMode = searchOrderModeSubmitDate;
			else if(orderMode == searchOrderModeVotesAverage)
				orderMode = searchOrderModeSubmitDate;
		}


		switch(orderMode)
		{
		case searchOrderModeRelevance:		// Non c' la rilevanza nelle search non basate sul Lucene.
											break;

		// TOCLEAN_SNAPSHOT_SCORE
		/* Per riprestinarlo, devo fare una join con la snapshot::users.
		case searchOrderModeReputation:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SCORE, DBTABLES::SNAPSHOT_OBJECTS_TABLE));
											select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::POSITION, DBTABLES::SNAPSHOT_OBJECTS_TABLE), order);
											break;
		*/

		case searchOrderModeSubmitDate:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), order);
											break;

		case searchOrderModeInsertDate:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::INSERT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), order);
											break;

		case searchOrderModePosition:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::POSITION, DBTABLES::SNAPSHOT_OBJECTS_TABLE), order);
											break;

		case searchOrderModeTitle:			select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::TITLE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), order);
											break;

		case searchOrderModeLastObject:		{
												select->tables.add(DbSqlTable(DBTABLES::DISCUSSIONS_STATS_TABLE));
												// Crea la join
												select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField(DBTABLES::DISCUSSIONS_STATS::REFERENCE, DBTABLES::DISCUSSIONS_STATS_TABLE));

												DbSqlField last_entry_date(DBTABLES::DISCUSSIONS_STATS::LAST_ENTRY_DATE, DBTABLES::DISCUSSIONS_STATS_TABLE);
												last_entry_date.setOrder(order);
												select->orderBy.fields.add(last_entry_date);
											}
											break;

		case searchOrderModeVotesTotal:		{
												select->tables.add(DbSqlTable(DBTABLES::DISCUSSIONS_STATS_TABLE));
												// Crea la join
												select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField(DBTABLES::DISCUSSIONS_STATS::REFERENCE, DBTABLES::DISCUSSIONS_STATS_TABLE));

												DbSqlField last_entry_date(DBTABLES::DISCUSSIONS_STATS::VOTES, DBTABLES::DISCUSSIONS_STATS_TABLE);
												last_entry_date.setOrder(order);
												select->orderBy.fields.add(last_entry_date);
											}
											break;

		case searchOrderModeVotesAverage:		{
												select->tables.add(DbSqlTable(DBTABLES::DISCUSSIONS_STATS_TABLE));
												// Crea la join
												select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField(DBTABLES::DISCUSSIONS_STATS::REFERENCE, DBTABLES::DISCUSSIONS_STATS_TABLE));

												DbSqlField last_entry_date(DBTABLES::DISCUSSIONS_STATS::VOTES_AVERAGE, DBTABLES::DISCUSSIONS_STATS_TABLE);
												last_entry_date.setOrder(order);
												select->orderBy.fields.add(last_entry_date);
											}
											break;

		default:				OS_EXCEPTION("Unknown query order mode");
								break;
		}
	}

	uint32 searchLimit = Options::instance()->getOption<uint32>(Options::portals_options::search_limit);

	if(searchLimit != 0)
	{
		// 0.12 RC5 - Altrimenti, setto cmq un massimo di risultati, come limite massimo ragionevole.
		select->limit.setCount(searchLimit);
	}

	if(query->hasMaxResults())
	{
		// 0.13 RC2
		select->limit.setCount(query->getMaxResults());
	}

	// Fa prima una "count" per sapere quanti risultati totali, ad esempio per calcolare le pagine del pager.
	// Poi, vengono estratti solo i record che servono alla pagina attuale (se non è il primo giro di un group-mode).
	select->count = true;

	DataTable result;
	if(database->execute(select, result))
	{
		OS_ASSERT(result.hasRow(0));
		m_totalResults = result.get(0, 0);

		if(m_totalResults > 0)	// In teoria non serve rieseguire la query se non ci sono risultati...
		{
			// Se è in groupMode, ed è il primo passaggio, controllo se è parziale.
			if( (query->getGroupMode()) && (objectsMap.empty()) )
				if( (searchLimit != 0) && (m_totalResults >= searchLimit) )
					m_partial = true;

			// Se non è in groupMode, o è il secondo passaggio, allora filtro per il pager.
			if( (!query->getGroupMode()) || (!objectsMap.empty()) )
			{
				uint32 limit=0;
				if( (query->hasLimit()) && (query->hasMaxResults()) )
					limit = std::min<uint32>(query->getLimit(), query->getMaxResults());
				else if(query->hasLimit())
					limit = query->getLimit();
				else if(query->hasMaxResults())
					limit = query->getMaxResults();

				if(limit != 0)
				{
					select->limit.setCount(limit);
					select->limit.setOffset(query->getOffset());
				}
			}
			else
			{
				if(searchLimit != 0)
				{
					// 0.12 RC5 - Altrimenti, setto cmq un massimo di risultati, come limite massimo ragionevole.
					select->limit.setCount(searchLimit);
				}
			}

			select->count = false;

			result.clear();
			if(database->execute(select, result))
			{
				for(uint32 r = 0; r < result.rows(); r++)
				{
					EntityID reference = static_cast<String>(result.get(r, DBTABLES::SNAPSHOT_OBJECTS::ENTITY)).to_ascii();
					if(query->getGroupMode())
					{
						shared_ptr<EntitiesEntity> entity = database->getPortal()->getEntity(database, reference);
						if( (entity != NULL) && (entity->getCurrent() != NULL) )
						{
							if(ObjectsSystem::instance()->getDescriptor(entity->getObjectType())->isGroupable())
								reference = static_cast<String>(result.get(r, DBTABLES::SNAPSHOT_OBJECTS::PARENT)).to_ascii();
						}
					}
					add(reference);
				}
			}
		}
	}
}