public function Query($objectclass, $criteria = null, $cache_timeout = null)
	{
		if (is_null($cache_timeout)) $cache_timeout = $this->ValueCacheTimeout;

		if (strlen($objectclass) < 1)
		{
			throw new Exception("\$objectclass argument is required");
		}

		// if criteria is null, then create a generic one
		if (is_null($criteria))
		{
			$criteria = new Criteria();
		}

		// see if this object has a custom query designated
		$custom = $this->GetCustomQuery($objectclass, $criteria);

		$sql = "";
		$count_sql = "";

		if ($custom)
		{
			$this->Observe("Using Custom Query",OBSERVE_DEBUG);
			$sql = $custom;

			// the counter query may be blank, in which case DataSet will generate one
			$count_sql = $this->GetCustomCountQuery($objectclass, $criteria);
		}
		else
		{
			// the first-level fieldmaps should be from the primary table
			$fms = $this->GetFieldMaps($objectclass);

			// the query builder will handle creating the SQL for us
			require_once("QueryBuilder.php");
			$builder = new QueryBuilder($this);
			$builder->RecurseFieldMaps($objectclass, $fms);

			$sql = $builder->GetSQL($criteria);

			$count_sql = $builder->GetCountSQL($criteria);
		}

		require_once("DataSet.php");
		$ds = new DataSet($this, $objectclass, $sql, $cache_timeout);
		$ds->CountSQL = $count_sql;
		$ds->UnableToCache = $cache_timeout === 0;

		return $ds;

	}