[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( &paramValues, &paramLengths, 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( &paramValues, &paramLengths, 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