Artigo: 235053 - Última revisão: segunda-feira, 3 de Novembro de 2003 - Revisão: 2.2

PROBLEMA: E_FAIL devolvido de Prepare() quando instrução de SQL contém um parâmetro de 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 | Reduzir tudo

Sintomas

Utilizando o fornecedor de OLE DB para SQL Server e chamar a função de CCommand::Prepare() ATL ou ICommandPrepare::Prepare(), devolverá E_FAIL com a seguinte descrição de erro:
Violação de acesso ou erro sintaxe.
O SQL Server fornecedor OLE DB fornecido com o MDAC 2.7 devolve a seguinte mensagem de erro melhoradas:
Informações sobre o parâmetro não pode ser derivado de instruções de SQL com consultas sub-select. Definir informações de parâmetros antes de preparar comandos.

Causa

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

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

Resolução

Tem de chamar CCommand::SetParameterInfo() ou ICommandWithParameters::SetParameterInfo() antes de chamar Prepare().

Consulte a secção mais informação deste artigo para código de exemplo que utiliza os modelos de consumidor ATL OLE DB e demonstra SetParameterInfo() chamada.

Ponto Da Situação

Este comportamento ocorre por predefinição.

Mais Informação

Passos para reproduzir o comportamento

  1. Crie duas tabelas numa base de dados Microsoft SQL Server: tabela1 deve ter um campo de carácter e um campo de número inteiro, tabela2 deve ter apenas um campo de número inteiro.
  2. Crie uma classe de descritor de acesso 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 utilizando a classe de descritor de acesso que acabou de criar. A classe CCommand deve semelhantes à 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, remova comentários à volta de código que chama SetParameterInfo() para impedir que Prepare() devolver E_FAIL.
  4. Finalmente, adicione algum código da aplicação 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 revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes 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/ )