Subscribe to News

Search by index non correlative columns on an SQL CE data base

Author : Ester Artieda

From TechnologicalWiki

Jump to: navigation, search


Contents

[edit] Introduction

This articule describes the way to use indexes to get non correlative colums as a result. This is very useful because we return only the columns we want without taking into account the original distribution or design of the table.

[edit] Background

Data bases are very useful tools when we want to manage structurated information. As it happens on PC, mobile devices have their own data bases. These data bases are smaller than PC's ones and have reduced options (security, multi-user...), but they have the capability of saving structurated data.

Particularly, on this article, we are going to use sql-ce, because is one of the most common data bases on windows mobile devices.

Altought it isn't installed by default on all the versions of windows mobile we can get its dlls and some samples on http://www.microsoft.com/downloads/details.aspx?familyid=E9AA3F8D-363D-49F3-AE89-64E1D149E09B&displaylang=en. One of these samples is the start point to this article, Northwind.sdf.

[edit] Code

This code help us to get only data we need independently of the distribution of columns on the table of the database. The trick is to add a new accessor to get the results which is different to the index accessor.

Initialization of variables:

       wstring profileTable::LoadTableInfo(WCHAR* login,wchar_t* table, wchar_t* index, wstring pwszProfiles,int numberOfFields)
       {
           HRESULT	 hr          = NOERROR;			// Error code reporting
           DBBINDING    *prgBinding = NULL;                     // Binding used to create accessor
           DBBINDING    *prgBinding2= NULL;                     // Binding used to create accessor2
           HROW	 rghRows[1];				        // Array of row handles obtained from the rowset object
           HROW         *prghRows   = rghRows;			// Row handle(s) pointer
           DBID	 TableID;                                       // Used to open/create table
           DBID         IndexID;                                // Used to create index
           DBPROPSET	 rowsetpropset[1];                      // Used when opening integrated index
           DBPROP       rowsetprop[1];                          // Used when opening integrated index
           ULONG        cRowsObtained = 0;                      // Number of rows obtained from the rowset object
           DBOBJECT     dbObject;                               // DBOBJECT data.
           DBCOLUMNINFO *pDBColumnInfo = NULL;                  // Record column metadata
           BYTE         *pData	= NULL;                         // record data
           WCHAR        *pStringsBuffer = NULL;
           DWORD        dwBindingSize = 0;
           DWORD        dwIndex = 0;
           DWORD        dwOffset = 0;
           DWORD        dwOrdinal = 0;
           ULONG	 ulNumCols;
           IOpenRowset  *pIOpenRowset = NULL;                   // Provider Interface Pointer
           IRowset      *pIRowset = NULL;                       // Provider Interface Pointer
           IRowsetIndex *pIRowsetIndex	= NULL;                 // Provider Interface Pointer
           IAccessor    *pIAccessor = NULL;                     // Provider Interface Pointer
           IAccessor    *pIAccessor2= NULL;                     // Provider Interface Pointer
           ILockBytes   *pILockBytes = NULL;                    // Provider Interface Pointer
           IColumnsInfo *pIColumnsInfo	= NULL;                 // Provider Interface Pointer
           HACCESSOR    hAccessor = DB_NULL_HACCESSOR;          // Accessor handle
           HACCESSOR    hAccessor2 = DB_NULL_HACCESSOR;         // Accessor handle

Initialize data to search:

           wstring resul=L"";
           WCHAR* pwszProfile[50]={L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",L"",...,L""};
           int endFields=0;
           const wchar_t* auxFields=L"";
           for (int i=0;i<numberOfFields;i++)
           {
               endFields=pwszProfiles.find(L";");
               wstring auxFields1(pwszProfiles.substr(0,endFields));//=(wchar_t*)malloc(pwszProfiles.substr(0,endFields).length());
               auxFields=auxFields1.c_str();
               wstring pwszProfiles1(pwszProfiles.substr(endFields+1));
               pwszProfiles=pwszProfiles1;
               pwszProfile[i]=new WCHAR[lstrlen(auxFields)+1];
               wcscpy(pwszProfile[i],auxFields);
           }
           VariantInit(&rowsetprop[0].vValue);

Create session and set up its properties:

           if (NULL == m_pIDBCreateSession)
           {
               hr = E_POINTER;
               goto Exit;
           }
           // Create a session object
           hr = m_pIDBCreateSession->CreateSession(NULL, IID_IOpenRowset, (IUnknown**) &pIOpenRowset);
           if(FAILED(hr))
           {
               goto Exit;
           }
           // Set up information necessary to open a table
           // using an index and have the ability to seek.
           //
           TableID.eKind = DBKIND_NAME;
           TableID.uName.pwszName = table;
           IndexID.eKind = DBKIND_NAME;
           IndexID.uName.pwszName = index;

Prepare the table to access with an index:

           // Request ability to use IRowsetChange interface
           //
           rowsetpropset[0].cProperties = 1;
           rowsetpropset[0].guidPropertySet= DBPROPSET_ROWSET;
           rowsetpropset[0].rgProperties = rowsetprop;
           rowsetprop[0].dwPropertyID = DBPROP_IRowsetIndex;
           rowsetprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
           rowsetprop[0].colid	= DB_NULLID;
           rowsetprop[0].vValue.vt= VT_BOOL;
           rowsetprop[0].vValue.boolVal= VARIANT_TRUE;
           // Open the table using the index
           //
           hr = pIOpenRowset->OpenRowset( NULL,
                                          &TableID,
                                          &IndexID,
                                          IID_IRowsetIndex,
                                          sizeof(rowsetpropset)/sizeof(rowsetpropset[0]),
                                          rowsetpropset,
                                          (IUnknown**) &pIRowsetIndex);
           if(FAILED(hr))
           {
               goto Exit;
           }
           // Get IRowset interface
           //
           hr = pIRowsetIndex->QueryInterface(IID_IRowset, (void**) &pIRowset);
           if(FAILED(hr))
           {
               goto Exit;
           }
           // Get IColumnsInfo interface
           //
           hr = pIRowset->QueryInterface(IID_IColumnsInfo, (void **)&pIColumnsInfo);
           if(FAILED(hr))
           {
               goto Exit;
           }

Save space to work with data base structure

          // Get the column metadata
          //
          hr = pIColumnsInfo->GetColumnInfo(&ulNumCols, &pDBColumnInfo, &pStringsBuffer);
          if(FAILED(hr) || 0 == ulNumCols)
          {
              goto Exit;
          }
          // Create a DBBINDING array.
          //
          dwBindingSize = numberOfFields;
          prgBinding = (DBBINDING*)CoTaskMemAlloc(sizeof(DBBINDING)*dwBindingSize);
          if (NULL == prgBinding)
          {
               hr = E_OUTOFMEMORY;
               goto Exit;
          }
          // Set initial offset for binding position
          //
          dwOffset = 0;
          // Prepare structures to create the accessor
          //
          for (dwIndex = 0; dwIndex < dwBindingSize; ++dwIndex)
          {
               if (!GetColumnOrdinal(pDBColumnInfo, ulNumCols, pwszProfile[dwIndex], &dwOrdinal))
               {
                    hr = E_FAIL;
                    goto Exit;
               }
               // Prepare structures to create the accessor
               //
               prgBinding[dwIndex].iOrdinal	= dwOrdinal;
               prgBinding[dwIndex].dwPart	= DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
               prgBinding[dwIndex].obLength	= dwOffset;
               prgBinding[dwIndex].obStatus	= prgBinding[dwIndex].obLength + sizeof(ULONG);
               prgBinding[dwIndex].obValue		= prgBinding[dwIndex].obStatus + sizeof(DBSTATUS);
               prgBinding[dwIndex].pTypeInfo	= NULL;
               prgBinding[dwIndex].pBindExt	= NULL;
               prgBinding[dwIndex].dwMemOwner	= DBMEMOWNER_CLIENTOWNED;
               prgBinding[dwIndex].dwFlags		= 0;
               prgBinding[dwIndex].bPrecision	= pDBColumnInfo[dwOrdinal].bPrecision;
               prgBinding[dwIndex].bScale	= pDBColumnInfo[dwOrdinal].bScale;
               switch(pDBColumnInfo[dwOrdinal].wType)
               {
               case DBTYPE_BYTES:		// Column "Photo" binding (BLOB)
                     // Set up the DBOBJECT structure.
                     //
                     dbObject.dwFlags = STGM_READ;
                     dbObject.iid	 = IID_ILockBytes;
                     prgBinding[dwIndex].pObject		= &dbObject;
                     prgBinding[dwIndex].cbMaxLen	= sizeof(IUnknown*);
                     prgBinding[dwIndex].wType		= DBTYPE_IUNKNOWN;
                     break;
               case DBTYPE_WSTR:
                     prgBinding[dwIndex].pObject = NULL;
                     prgBinding[dwIndex].wType	= pDBColumnInfo[dwOrdinal].wType;
                     prgBinding[dwIndex].cbMaxLen= sizeof(WCHAR)*(pDBColumnInfo[dwOrdinal].ulColumnSize + 1);// +1=>null termination
                     break;
               default:
                     prgBinding[dwIndex].pObject = NULL;
                     prgBinding[dwIndex].wType	= pDBColumnInfo[dwOrdinal].wType;
                     prgBinding[dwIndex].cbMaxLen = pDBColumnInfo[dwOrdinal].ulColumnSize;
                     break;
               }
               // Calculate new offset
               //
               dwOffset = prgBinding[dwIndex].obValue + prgBinding[dwIndex].cbMaxLen;
               // Properly align the offset
               //
               dwOffset = ROUND_UP(dwOffset, COLUMN_ALIGNVAL);
          }

Prepare structures to create the second accessor:

          ULONG ncol;
          DBINDEXCOLUMNDESC*		pColDesc;
          ULONG				nPropSet;
          DBPROPSET*			pPropSet;
          hr = pIRowsetIndex->GetIndexInfo(&ncol, // Number of index columns
                                           &pColDesc,	// Names of columns
                                           &nPropSet,	// Don't care
                                           &pPropSet);	// Don't care
          if(FAILED(hr))
              goto Exit;
          prgBinding2 = (DBBINDING*)CoTaskMemAlloc(sizeof(DBBINDING) * ncol);
          if(prgBinding2)
          {
               DWORD	dwOffset = 0,
               dwOrdinal;
               for(int i = 0; i < ncol; ++i)
               {
                   if (!GetColumnOrdinal(pDBColumnInfo, ulNumCols,pColDesc[i].pColumnID->uName.pwszName, &dwOrdinal))
                   {
                          hr = E_FAIL;
                          goto Exit;
                   }
                   prgBinding2[i].iOrdinal	= dwOrdinal;
                   prgBinding2[i].dwPart	= DBPART_VALUE | DBPART_STATUS | DBPART_LENGTH;
                   prgBinding2[i].obLength	= dwOffset;
                   prgBinding2[i].obStatus	= prgBinding2[i].obLength + sizeof(ULONG);
                   prgBinding2[i].obValue	= prgBinding2[i].obStatus + sizeof(DBSTATUS);
                   prgBinding2[i].pTypeInfo	= NULL;
                   prgBinding2[i].pObject	= NULL;
                   prgBinding2[i].pBindExt	= NULL;
                   prgBinding2[i].dwMemOwner	= DBMEMOWNER_CLIENTOWNED;
                   prgBinding2[i].dwFlags	= 0;
                   prgBinding2[i].wType	= pDBColumnInfo[dwOrdinal].wType;
                   prgBinding2[i].bPrecision	= pDBColumnInfo[dwOrdinal].bPrecision;
                   prgBinding2[i].bScale	= pDBColumnInfo[dwOrdinal].bScale;
                   prgBinding2[i].pTypeInfo	= (ITypeInfo*)dwOffset;
                   switch(prgBinding2[i].wType)
                   {
                   case DBTYPE_WSTR:
                         prgBinding2[i].cbMaxLen = sizeof(wchar_t)*(pDBColumnInfo[dwOrdinal].ulColumnSize + 1);//+1=>nul termination
                         break;
                   default:
                         prgBinding2[i].cbMaxLen = pDBColumnInfo[dwOrdinal].ulColumnSize;
                         break;
                   }
                   // Calculate new offset
                   //
                   dwOffset = prgBinding2[i].obValue + prgBinding2[i].cbMaxLen;
                   // Properly align the offset
                   //
                   dwOffset = ROUND_UP(dwOffset, COLUMN_ALIGNVAL);
                   }
                   //pData = (BYTE*)CoTaskMemAlloc(dwOffset);
                   pData = (BYTE*)CoTaskMemAlloc(1000);
                   if(NULL == pData)
                        goto Exit;
                   // Set data buffer to zero
                   //
                   memset(pData, 0, dwOffset);
          }

Create accessor to seek:

          // Get IAccessor interface
          //
          hr = pIRowset->QueryInterface(IID_IAccessor, (void**)&pIAccessor2);
          if(FAILED(hr))
          {
              goto Exit;
          }
          // Create accessor.
          //
          hr = pIAccessor2->CreateAccessor(DBACCESSOR_ROWDATA,
                                           dwBindingSize,
                                           prgBinding,
                                           0,
                                           &hAccessor,
                                           NULL);
          if(FAILED(hr))
          {
              goto Exit;
          }
          // Create accessor2.
          //
          hr = pIAccessor2->CreateAccessor(DBACCESSOR_ROWDATA,
                                           ncol,
                                           prgBinding2,
                                           0,
                                           &hAccessor2,
                                           NULL);
          if(FAILED(hr))
          {
              goto Exit;
          }

Prepare structure to seek and seek data:

          // Set data buffer for seek operation
          //
          *(DBSTATUS*)(pData+prgBinding2[0].obStatus)	= DBSTATUS_S_OK;
          wcscpy((WCHAR*)(pData+prgBinding2[0].obValue),login);
          *(ULONG*)(pData+prgBinding2[0].obLength) = wcslen((WCHAR*)(pData+prgBinding2[0].obValue))*sizeof(WCHAR);
          // Position at a key value within the current range
          //
          hr = pIRowsetIndex->Seek(hAccessor2, 1, pData, DBSEEK_FIRSTEQ);
          if(FAILED(hr))
          {
              goto Exit;
          }

Get data if it has been found:

         // Retrieve a row handle for the row resulting from the seek
         //
         hr = pIRowset->GetNextRows(DB_NULL_HCHAPTER, 0, 1, &cRowsObtained, &prghRows);
         if(FAILED(hr))
         {
             goto Exit;
         }
         if (DB_S_ENDOFROWSET != hr)
         {
             // Fetch actual data
             //
             hr = pIRowset->GetData(prghRows[0], hAccessor, pData);
             if (FAILED(hr))
             {
                  goto Exit;
             }
             for(int i=0;i<dwBindingSize;i++)
             {
                  if (DBSTATUS_S_ISNULL != *(DBSTATUS *)(pData+prgBinding[i].obStatus) &&
                      DBSTATUS_S_OK == *(DBSTATUS *)(pData+prgBinding[i].obStatus))
                  {
                      wchar_t* aux=(WCHAR*)(pData+prgBinding[i].obValue);
                      resul=resul+wstring(aux)+L";";
                  }
             }
         }
         // Release the rowset.
         //
         pIRowset->ReleaseRows(1, prghRows, NULL, NULL, NULL);

Free memory:

 Exit:
         // Clear Variants
         //
         VariantClear(&rowsetprop[0].vValue);
         // Free allocated DBBinding memory
         //
         if (prgBinding)
         {
             CoTaskMemFree(prgBinding);
             prgBinding = NULL;
         }
         if (prgBinding2)
         {
             CoTaskMemFree(prgBinding2);
             prgBinding = NULL;
         }
         // Free allocated column info memory
         //
         if (pDBColumnInfo)
         {
             CoTaskMemFree(pDBColumnInfo);
             pDBColumnInfo = NULL;
         }
         // Free allocated column string values buffer
         //
         if (pStringsBuffer)
         {
             CoTaskMemFree(pStringsBuffer);
             pStringsBuffer = NULL;
         }
         // Free data record buffer
         //
         if (pData)
         {
             CoTaskMemFree(pData);
             pData = NULL;
         }
         // Release interfaces
         //
         if(pILockBytes)
         {
             pILockBytes->Release();
         }
         if(pIAccessor2)
         {
             pIAccessor2->ReleaseAccessor(hAccessor, NULL);
             pIAccessor2->ReleaseAccessor(hAccessor2, NULL);
             pIAccessor2->Release();
         }
         if (pIColumnsInfo)
         {
             pIColumnsInfo->Release();
         }
         if(pIRowset)
         {
             pIRowset->Release();
         }
         if (pIRowsetIndex)
         {
             pIRowsetIndex->Release();
         }
         if(pIOpenRowset)
         {
             pIOpenRowset->Release();
         }
         return resul;
 }

[edit] References

If you need more info about sql-ce databases you could find it on:

http://nativemobile.blogspot.com/search/label/SQL%20Compact

http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=7006&atb.perform(details)=&

http://www.pocketpcdn.com/articles/atl_ole_db.html

http://www.pocketpcdn.com/articles/articles.php?&atb.set(c_id)=74&atb.set(a_id)=3892&atb.perform(details)=&

Main Collaborators