ID do artigo: 235053 - Última revisão: segunda-feira, 3 de novembro de 2003 - Revisão: 2.2

PROBLEMA: E_FAIL retornado da Prepare() quando a instrução SQL contém um parâmetro em uma subconsulta

Dica do SistemaEste artigo aplica-se a um sistema operativo diferente do que está a utilizar. Foi desactivado o conteúdo do artigo, que pode não ser relevante para si.

Nesta página

Expandir tudo | Recolher tudo

Sintomas

Usando o provedor OLE DB para SQL Server e chamar a função CCommand::Prepare() ATL ou ICommandPrepare::Prepare(), retornará E_FAIL com a seguinte descrição do erro:
Violação de acesso ou erro sintaxe.
O SQL Server provedor OLE DB que vem com o MDAC 2.7 retorna a seguinte mensagem de erro aprimorada:
Informações de parâmetro não podem ser derivadas de instruções SQL com consultas sub-select. Definir informações de parâmetro antes de preparar comando.

Causa

O texto de comando SQL para o objeto OLE DB Command contém um parâmetro em uma subconsulta. Por exemplo, a instrução SQL a seguir faz com que o erro:
SELECT * FROM Table1 WHERE field2 IN <BR/>
(SELECT field1 FROM Table2 where field1 > ?)
				

O provedor Microsoft OLE DB para SQL Server não pode derivar informações de parâmetro de subconsultas.

Resolução

Você deve chamar CCommand::SetParameterInfo() ou ICommandWithParameters::SetParameterInfo() antes de chamar Prepare().

Consulte a seção mais informações deste artigo para obter um exemplo de código que usa os modelos de consumidor ATL OLE DB e demonstra SetParameterInfo() chamada.

Situação

Esse comportamento é por design.

Mais Informações

Etapas para reproduzir o problema

  1. Criar duas tabelas em um banco de dados do Microsoft SQL Server: Tabela1 deve ter um campo de caractere e um campo inteiro, Tabela2 deve ter somente um campo inteiro.
  2. Crie uma classe acessador semelhante à seguinte:
    class CQuery1Accessor
    {
    public:
    	TCHAR m_field1[11];
    	LONG  m_field2;
    	LONG  m_field1param;
    
    BEGIN_COLUMN_MAP(CQuery1Accessor)
    	COLUMN_ENTRY(1, m_field1)
    	COLUMN_ENTRY(2, m_field2)
    
    END_COLUMN_MAP()
    
    BEGIN_PARAM_MAP(CQuery1Accessor)
    	COLUMN_ENTRY(1,m_field1param)
    END_PARAM_MAP()
    DEFINE_COMMAND(CQuery1Accessor, _T("SELECT * FROM Table1 WHERE field2 IN"
    			   "(SELECT field1 FROM Table2 where field1 > ?)"));
    
    	// You may want to call this function if you are inserting a record and want to
    	// initialize all the fields, if you are not going to explicitly set all of them.
    	void ClearRecord()
    	{
    		memset(this, 0, sizeof(*this));
    	}
    };
    
    						
  3. Crie uma classe CCommand que executa o comando usando a classe de acessador que recém-criado. A classe CCommand deve semelhante ao seguinte:
    class CQuery1 : public CCommand<CAccessor<CQuery1Accessor> >
    {
    public:
    	HRESULT Open()
    	{
    		HRESULT		hr;
    
    
    		hr = OpenDataSource();
    		if (FAILED(hr))
    			return hr;
    
    		return OpenRowset();
    	}
    	HRESULT OpenDataSource()
    	{
    		HRESULT		hr;
    		CDataSource db;
    		CDBPropSet	dbinit(DBPROPSET_DBINIT);
    
    		dbinit.AddProperty(DBPROP_AUTH_PERSIST_SENSITIVE_AUTHINFO, false);
    		dbinit.AddProperty(DBPROP_INIT_CATALOG, OLESTR("yourdatabase"));
    		dbinit.AddProperty(DBPROP_INIT_DATASOURCE, OLESTR("yourserver"));
    		dbinit.AddProperty(DBPROP_INIT_LCID, (long)1033);
    		dbinit.AddProperty(DBPROP_INIT_PROMPT, (short)4);
    		dbinit.AddProperty(DBPROP_AUTH_PASSWORD, "");
    		dbinit.AddProperty(DBPROP_AUTH_USERID, "sa");
    
    		hr = db.Open(_T("SQLOLEDB"), &dbinit);
    		if (FAILED(hr))
    			return hr;
    
    		return m_session.Open(db);
    	}
    	HRESULT OpenRowset()
    	{
    		// Set properties for open
    		LPCTSTR szCommand = NULL;
    		HRESULT hr = S_OK;
    		hr = _CommandClass::GetDefaultCommand(&szCommand);
    		if (FAILED(hr))
    			return hr;
    		hr = CreateCommand(m_session);
    		if (SUCCEEDED(hr))
    		{
    			CComPtr<ICommandText> spCommandText;
    			hr = m_spCommand->QueryInterface(&spCommandText);
    			USES_CONVERSION;
    			if (SUCCEEDED(hr))
    			hr = spCommandText->SetCommandText(DBGUID_SQL, T2COLE(szCommand));
    		}
    /* --------------  Adding this code prevents the error:
    		ULONG ulOrds[]={1};
                    DBPARAMBINDINFO ParamInfo[1];
    
    		ParamInfo[0].pwszDataSourceType = (unsigned short *) L"DBTYPE_I4";
    		ParamInfo[0].bPrecision = 10;
    		ParamInfo[0].bScale = 0;
    		ParamInfo[0].dwFlags = DBPARAMFLAGS_ISINPUT;
    		ParamInfo[0].pwszName = NULL;
    
    		ParamInfo[0].ulParamSize = sizeof(LONG);
    
    		hr = SetParameterInfo(1, ulOrds, ParamInfo);
    ----------------*/ 
    		hr = Prepare(); //// hr =  E_FAIL without SetParameterInfo call
    		if (E_FAIL == hr)
    		{
    			AtlTraceErrorRecords();
    			return E_FAIL;
    		}
    
    		m_field1param = 0;
    		hr = CCommand<CAccessor<CQuery1Accessor> >::Open();
    		return hr;
    	}
    	CSession	m_session;
    };
    
    
    						
    No código acima, remova os comentários ao redor o código que chama SetParameterInfo() para impedir que Prepare() retornar E_FAIL.
  4. Finalmente, adicione algum código em seu aplicativo que abre a consulta:
    	CoInitialize(NULL);
    	CQuery1 rs;
    	rs.Open();
    	rs.MoveFirst();
    						

A informação contida neste artigo aplica-se a:
  • Microsoft OLE DB Provider for SQL Server 7.01 nas seguintes plataformas
    • Microsoft Data Access Components 2.0
    • Microsoft Data Access Components 2.1
    • Microsoft Data Access Components 2.5
    • Microsoft Data Access Components 2.6
    • Microsoft Data Access Components 2.7
  • Microsoft OLE DB Provider for SQL Server 7.0 nas seguintes plataformas
    • Microsoft Data Access Components 2.0
    • Microsoft Data Access Components 2.1
    • Microsoft Data Access Components 2.5
    • Microsoft Data Access Components 2.6
    • Microsoft Data Access Components 2.7
Palavras-chave: 
kbmt kbconsumer kbdatabase kbdtl kbprb KB235053 KbMtpt
Tradução automáticaTradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 235053  (http://support.microsoft.com/kb/235053/en-us/ )