Ejemplo n.º 1
0
shared_ptr<EntitiesEntities> EntitiesEntity::getChilds(const shared_ptr<IPortalDatabase> &database, const ObjectsTypes &types, const RangeUint32 &range, CommonOrder order) const
{
	shared_ptr<DbSqlSelect> select;
	getChildsStatement(database, types, range, false, false, false, select);

	switch(order)
	{
	case coSubmitDateAsc:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField::foAsc);
								break;

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

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

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

	default:					OS_EXCEPTION("Invalid order");
								break;
	}

	return getChilds(database, types, range, select);
}
Ejemplo n.º 2
0
shared_ptr<EntitiesEntities> EntitiesEntity::getChilds(const shared_ptr<IPortalDatabase> &database, const ExtensionsComponentID &component, const RangeUint32 &range, CommonOrder order) const
{
	OS_TIMER_PERFORMANCE(TP, _S("Entity::getChilds"));
	shared_ptr<DbSqlSelect> select;
	getChildsStatement(database, portalObjectTypeSection, range, false, false, false, select);
	// Aggiunge alla select la tabella delle sezioni
	select->tables.add(DbSqlTable(DBTABLES::SECTIONS_TABLE));
	// Crea la join tra la tabella di cache e quella delle sezioni
	select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::CURRENT, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField(DBTABLES::SECTIONS::ID, DBTABLES::SECTIONS_TABLE));
	// Seleziona il componente specificato
	select->where.add(DbSqlField(DBTABLES::SECTIONS::COMPONENT, DBTABLES::SECTIONS_TABLE), Convert::toSQL(component.toUTF16()));

	switch(order)
	{
	case coSubmitDateAsc:		select->orderBy.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), DbSqlField::foAsc);
								break;

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

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

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

	default:					OS_EXCEPTION("Invalid order");
								break;
	}

	return getChilds(database, portalObjectTypeSection, range, select);
}
Ejemplo n.º 3
0
void EntitiesEntity::getChildsStatement(const shared_ptr<IPortalDatabase> &database, const ObjectsTypes &types, const RangeUint32 &range, bool count, bool includeSystem, bool includeInvisible, shared_ptr<DbSqlSelect> &statement) const
{
	OS_LOCK(m_cs);

	// Nota: qui bisogna specificare sempre la tabella perch dall'esterno la select pu essere messa in join con altre tabelle

	shared_ptr<DbSqlSelect> select(OS_NEW DbSqlSelect(DBTABLES::SNAPSHOT_OBJECTS_TABLE));
	if(count)
		select->count = true;
	else
		select->fields.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE));

	database->getPortal()->getSnapshotManager()->ensureChilds(database, getEntityID());
	select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::PARENT, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(getEntityID()));

	// Genera il filtro sui tipi di figli
	StringList childsTypes;
	for(ObjectsTypes::const_iterator i = types.begin(); i != types.end(); ++i)
	{
		if((*i) != portalObjectTypeUnknown)
			childsTypes.push_back(Convert::toSQL(static_cast<uint32>(*i)));
	}

	// Se  stato specificato un filtro sul tipo di figli lo applica
	if(childsTypes.empty() == false)
	{
		select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::TYPE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), childsTypes);
	}

	// Includi le sezioni di sistema (virtuali)?
	// Sono figlie della root, per cui la condizione ha senso solo in quel caso
	if(getEntityID() == ObjectsSystem::instance()->getRootID())
	{
		if(includeSystem == true)
		{
			// Salta la root stessa
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::ENTITY, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(ObjectsSystem::instance()->getRootID()), DbSqlCondition::cfDifferent | DbSqlCondition::cfAnd);
		}
		else
		{
			// VERYURGENT: Le classi statement non hanno una "not in"... poco male, ma userebbe meglio l'indice.
			select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::INSERT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(DateTime::EMPTY), DbSqlCondition::cfDifferent | DbSqlCondition::cfAnd);
		}
	}

	if(includeInvisible == false)
		select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::VISIBLE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(true));

	uint32 size = range.size();
	if(size != 0)
		select->limit.setCount(size);

	uint32 start = range.start();
	if(start != 0)
		select->limit.setOffset(start);

	statement = select;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
String CommentableObjectViewer::localizePost(const EntityID &id)
{
	String href;

	shared_ptr<EntitiesEntity> entity = getPortal()->getEntity(getDatabase(), id);
	if(entity != nullptr)
	{
		shared_ptr<ObjectsPost> post = objects_post_cast(entity->getCurrent());
		if(post != nullptr)
		{
			shared_ptr<EntitiesEntity> parent_entity = getPortal()->getEntity(getDatabase(), post->getParent());
			if(parent_entity != nullptr)
			{
				shared_ptr<DbSqlSelect> select;
				// Ottiene la select per l'estrazione dei posts
				parent_entity->getChildsStatement(getDatabase(), portalObjectTypePost, RangeUint32::EMPTY, true, false, false, select);
				// Aggiunge come limite la data del post specificato per localizzarne l'indice
				select->where.add(DbSqlField(DBTABLES::SNAPSHOT_OBJECTS::SUBMIT_DATE, DBTABLES::SNAPSHOT_OBJECTS_TABLE), Convert::toSQL(entity->getEntitySubmitDate()), DbSqlCondition::cfMinor | DbSqlCondition::cfEqual | DbSqlCondition::cfAnd);

				ordered_map<std::wstring, std::wstring> params;
				// Calcola il numero di posts fino a quello specificato
				uint32 count = parent_entity->getChildsCount(getDatabase(), portalObjectTypePost, select);
				if(count > 0)
				{
					// Ottiene il numero
					uint32 pager_items = getSkin()->getPagerItems();
					// Calcola l'offset per la visualizzazione del post
					uint32 offset = static_cast<uint32>(count/pager_items)*pager_items;
					if(offset > 0)
						params.set(OS_URL_PARAM_OFFSET, conversions::to_wstring(offset));
				}

				// Genera un link al padre con ancora l'id del post
				href = HttpParser::createAnchor(parent_entity->getViewLink(getPortal(), params), entity->getEntityID().getString());
			}
		}
	}

	return href;
}
Ejemplo n.º 6
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);
				}
			}
		}
	}
}