[Oledb-dev] Is it time for 1.0.0.20?
Victor Snezhko
snezhko at indorsoft.ru
Mon Apr 17 15:59:53 UTC 2006
Hmm, seems that mailman doesn't like attachments that are inside of
the text. Sigh, reposting again:
Victor Snezhko <snezhko at indorsoft.ru> writes:
> Sorry, I haven't properly replied to the previous e-mail, and both
> my and your reply didn't reach the list.
>
>> Now, here's the thing.
>>
>> The way I read the docs, there are two ways for OLE DB to know what
>> types are passed inside the question marks. Either it is specifically
>> set using "SetParameterInfo", or the command is an incomplete command ({
>> call proc }), in which case the provider queries the database and find
>> out what they are.
>>
>> I have not, however, heared of a case where, using a normal query, the
>> provider just guesses what the types should be.
>>
>> What were the types of the parameters passed in practice?
>
> Just now I noticed that I can know DBTYPE's through DBBINDING
> structures that I obtain via GetBindings();
> At last I can throw all that ugly parsing away.
>
> So. Now that we have parameter types, we can shift initialization (and
> allocation) of paramTypes and paramValues to the middle of
> FillInValues, where the actual number of parameters is certainly
> known. It'll require FillInValues interface change, but new call
> string (from the patch below) looks even nicer to me:
>
> hr=FillinValues( ¶mValues, ¶mLengths, num_params, ...
>
> Here we emphasize that values and lengths are definitely changing
> inside FillInValues.
>
> Here is an experimental patch, any testing is welcome.
> I can't claim that it's working, as something has broken in my
> environment, and instead of string parameters I receive nulls.
> I'll investigate it later.
>
>
> Index: PgCommand.cpp
> ===================================================================
> RCS file: /cvsroot/oledb/oledb/PgCommand.cpp,v
> retrieving revision 1.24
> diff -u -r1.24 PgCommand.cpp
> --- PgCommand.cpp 9 Apr 2006 13:37:26 -0000 1.24
> +++ PgCommand.cpp 17 Apr 2006 15:20:42 -0000
> @@ -247,25 +247,31 @@
> //command+=szCommand;
>
> size_t num_params=m_params.size();
> - auto_array<unsigned int> paramTypes(new unsigned int [num_params]);
> - auto_array<char *> paramValues(new char *[num_params]);
> - auto_array<int> paramLengths(new int[num_params]);
> - auto_array<int> paramFormats(new int[num_params]);
> -
> - for( unsigned int i=0; i<num_params; ++i ) {
> - paramTypes[i]=m_params[i].oid;
> - paramFormats[i]=1;
> - }
> + auto_array<char *> paramValues;
> + auto_array<int> paramLengths;
>
> auto_array<char> databuff;
>
> - hr=FillinValues( paramValues.get(), paramLengths.get(), num_params, pParams, pgsess,
> + hr=FillinValues( ¶mValues, ¶mLengths, num_params, pParams, pgsess,
> databuff );
>
> if( FAILED(hr) ) {
> throw PgOleError(hr, "FillinValues failed");
> }
>
> + // FillInValues may change number of parameters if parameters were specified in pParams,
> + // but not via SetParameterInfo
> +
> + num_params=m_params.size();
> +
> + auto_array<unsigned int> paramTypes(new unsigned int [num_params]);
> + auto_array<int> paramFormats(new int[num_params]);
> +
> + for( unsigned int i=0; i<num_params; ++i ) {
> + paramTypes[i]=m_params[i].oid;
> + paramFormats[i]=1;
> + }
> +
> // We need to be inside a transaction if we are to get MultipleResults answers
> // Since only "select" will ever return MultipleResults, and as "Create table" will
> // fail if executed inside a transaction, make sure this is a select
> @@ -888,9 +894,12 @@
> return hr;
> }
>
> -HRESULT CPgCommand::FillinValues( char *paramValues[], int paramLengths[], size_t num_params,
> +HRESULT CPgCommand::FillinValues( auto_array<char *> *paramValues, auto_array<int> *paramLengths, size_t num_params,
> DBPARAMS * pParams, CPgSession *sess, auto_array<char> &buffer )
> {
> + if( paramValues==NULL || paramLengths==NULL )
> + return E_POINTER;
> +
> if( num_params==0 && pParams==NULL )
> return S_OK;
>
> @@ -913,13 +922,42 @@
> throw(hr);
>
> if( cBindings!=num_params )
> - throw(DB_E_PARAMNOTOPTIONAL);
> + {
> + // Parameter binding information were specified earlier, but for
> + // the different number of parameters. We will not make any
> + // decision in this case.
> + if( num_params != 0 )
> + {
> + throw(DB_E_PARAMNOTOPTIONAL);
> + }
> + else
> + {
> + m_params.resize(cBindings);
> + for( unsigned int i=0; i<cBindings; ++i)
> + {
> + USES_CONVERSION;
> + m_params[i].wType=rgBindings[i].wType;
> + m_params[i].oid=sess->GetOIDType(m_params[i].wType);
> + if( m_params[i].oid==0 ) {
> + ATLTRACE2(atlTraceDBProvider, 3, "CPgCommand::FillInValues DBTYPE oid lookup failed\n");
> + return DB_E_BADTYPENAME;
> + }
> +
> + //m_params[i].ulParamSize=rgBindings[i].ulParamSize;
> + m_params[i].bPrecision=rgBindings[i].bPrecision;
> + m_params[i].bScale=rgBindings[i].bScale;
> + }
> + num_params=m_params.size();
> + }
> + }
>
> size_t buffsize=0;
> std::vector<size_t> offsets;
> std::vector<DWORD> statuses;
> offsets.resize(cBindings);
> statuses.resize(cBindings);
> + *paramValues=auto_array<char*>(new char*[cBindings]);
> + *paramLengths=auto_array<int>(new int[cBindings]);
>
> for( unsigned int i=0; i<cBindings; ++i ) {
> ATLASSERT((i+1)==rgBindings[i].iOrdinal);
> @@ -937,9 +975,9 @@
> }
>
> offsets[i]=buffsize;
> - paramLengths[i]=GetPGWidth( info, &rgBindings[i], pParams->pData, &(statuses[i]),
> + (*paramLengths)[i]=GetPGWidth( info, &rgBindings[i], pParams->pData, &(statuses[i]),
> m_spConvert, sess );
> - buffsize+=paramLengths[i];
> + buffsize+=(*paramLengths)[i];
>
> if( statuses[i]==DBSTATUS_S_IGNORE ) {
> // Status is not valid for parameters
> @@ -953,17 +991,17 @@
> if( statuses[i]==DBSTATUS_S_OK ) {
> const typeinfo *info=sess->GetTypeInfo(m_params[i].oid);
>
> - paramValues[i]=buffer.get()+offsets[i];
> + (*paramValues)[i]=buffer.get()+offsets[i];
>
> hr=PGCopy( info, &rgBindings[i], pParams->pData, buffer.get()+offsets[i],
> - paramLengths[i], m_spConvert, sess );
> + (*paramLengths)[i], m_spConvert, sess );
>
> if( FAILED(hr) )
> throw(hr);
> } else {
> // If the status is non-fatal (or an exception would be raised at the getwidth
> // stage), but also not ok. Pass a NULL as parameter.
> - paramValues[i]=NULL;
> + (*paramValues)[i]=NULL;
> }
> }
> } catch(HRESULT res) {
> Index: TypeInfo.h
> ===================================================================
> RCS file: /cvsroot/oledb/oledb/TypeInfo.h,v
> retrieving revision 1.19
> diff -u -r1.19 TypeInfo.h
> --- TypeInfo.h 15 Apr 2006 11:39:41 -0000 1.19
> +++ TypeInfo.h 17 Apr 2006 15:32:02 -0000
> @@ -148,7 +148,7 @@
> colinfo->ulColumnSize=~0;
> if( colinfo->ulColumnSize<0 )
> colinfo->ulColumnSize=~0;
> - colinfo->dwFlags=DBCOLUMNFLAGS_MAYBENULL|
> + colinfo->dwFlags=DBCOLUMNFLAGS_MAYBENULL|DBCOLUMNFLAGS_WRITE|
> (colinfo->ulColumnSize==~0?0:DBCOLUMNFLAGS_ISFIXEDLENGTH);
> colinfo->wType=DBTYPE_UDT; // User Defined Type
> colinfo->bPrecision=~0;
>
>> In particular, did the parameter passed to the second question mark
>> of type DWORD?
>> If so, we may have no choice but to query the database about it. I'm not
>> Postgresql even has the mechanism to tell us what the parameters for a
>> prepared statement should be.
>
> Here is the part of a message that I wrote before knowing about
> GetBindings() DBTYPES. It can be useful anyway:
> ==============================================================================
> I asked postgresql for types by the following query:
>
> select pg_attribute.atttypid from pg_attribute left join pg_type on pg_attribute.attrelid = pg_type.typrelid
> where pg_attribute.attname ILIKE PARAM_NAME AND pg_type.typname ILIKE TABLENAME";
>
> PARAM_NAME and TABLE_NAME are a result of parsing SQL UPDATE statement.
>
> This way I have the oids, happily fill m_params, and that m_params[].oid are
> successfully used by FillInValues() later, matching the data that was
> supplied in parameters.
> Ah, one moment, I saw databuff (auto_array<char>) (declared in
> Execute()) overflowed, but didn't investigate this yet.
> ================================================================================
>
>>>>>My temporary "solution": When cBindings!=num_params, I just added
>>>>>parsing of the query to find names of parameters, and by names I
>>>>>retrieved oids of them. Parsing is done via pcre, thus adding one more
>>>>>dependency to the project.
>>>>>
>>>>>
>> Forget the question of whether we should parse the statements we pass to
>> Postgresql for a sec.
>
> This was the quote of the message in which I mentioned this hack for
> the first time...
>
>> How did you, in actuality, find out the right types? You don't know
>> them. Only Postgres does. Did you perform query based on column
>> types?
>
> Yes.
>
>>>everything else is available (when I implemented
>>>the hack described above, INSERTs actually passed real data).
>>>
>>>
>> If we have the DBTYPE of the var we can, quite easilly, convert it to
>> oid. That is, in fact, what SetParametersInfo does.
>>
>> I'm just wondering - where did the other info come from? It may be the
>> time that passed since last I worked on the provider, but I could not
>> find anything that gives us the DBTYPE except SetParameterInfo.
>
> Until now I didn't know too :)
> Now I wonder why is SetParameterInfo needed at all...
--
WBR, Victor V. Snezhko
EMail: snezhko at indorsoft.ru
More information about the Oledb-devel
mailing list