Showing posts with label parameter. Show all posts
Showing posts with label parameter. Show all posts

Sunday, March 25, 2012

Calculated Measure on SSAS 2005

Dear All,

I have a problem when I made calculation on SSAS 2005. I have two dimensions such as Department and Parameter where 1 Department has several Parameters.

Each Parameter has point measure (Total Point Parameter) and bobot measure in percent (Bobot Parameter). The subtotal of Total Point Parameter is sum of Total Point Parameter for parameters in 1 department and the subtotal of Bobot Parameter is sum of Bobot Parameter for parameters in 1 department which the result will be 100%. I want to make a calculated measure named Total Point Department that I can get the result by multiplying Total Point Parameter with Bobot Parameter. But for the subtotal of that calculated measure, the value should be sum of Total Point Department for parameters in 1 Department. I attach the layout so you can have a good understanding to my problem.

Department

Parameter

Total Point Parameter

Bobot Parameter

Total Point Department



KREDIT

FPD

80.56

25.00%

20.14



NBP

95.49

25.00%

23.87



OVERDUE BPKB

96.17

10.00%

9.62



OVERRIDE SCORING

110.00

10.00%

11.00



POOLING ORDER

35.00

30.00%

10.50



Total

417.21

100.00%

417.21

--> it should be

75.13

AR

AR ALIR ACTUAL

90.73

30.00%

27.22



AR ALIR ACTUAL VS TARGET

1.00

20.00%

0.20



AR LANCAR ACTUAL

200.00

30.00%

60.00



AR LANCAR ACTUAL VS TARGET

222.22

20.00%

44.44



Total

223.25

100.00%

223.25

--> it should be

131.86

Grand Total

640.46

200.00%

1280.92




This is the MDX script for Total Point Department:

[Measures].[Bobot Parameter]

* [Measures].[Total Point Parameter]


Can you please help me? Thanks in advance.

Regards,

I have the same issue, have you been able to solve your problem?

|||

Have you tried setting this up use a measure expression instead of a calculated measure?

I think this will make the multiplication happen at the leaf level and then the normal aggregation will kick in.

Otherwise you could try scoping your calculation at the leaf level.

Calculated Measure on SSAS 2005

Dear All,

I have a problem when I made calculation on SSAS 2005. I have two dimensions such as Department and Parameter where 1 Department has several Parameters.

Each Parameter has point measure (Total Point Parameter) and bobot measure in percent (Bobot Parameter). The subtotal of Total Point Parameter is sum of Total Point Parameter for parameters in 1 department and the subtotal of Bobot Parameter is sum of Bobot Parameter for parameters in 1 department which the result will be 100%. I want to make a calculated measure named Total Point Department that I can get the result by multiplying Total Point Parameter with Bobot Parameter. But for the subtotal of that calculated measure, the value should be sum of Total Point Department for parameters in 1 Department. I attach the layout so you can have a good understanding to my problem.

Department

Parameter

Total Point Parameter

Bobot Parameter

Total Point Department



KREDIT

FPD

80.56

25.00%

20.14



NBP

95.49

25.00%

23.87



OVERDUE BPKB

96.17

10.00%

9.62



OVERRIDE SCORING

110.00

10.00%

11.00



POOLING ORDER

35.00

30.00%

10.50



Total

417.21

100.00%

417.21

--> it should be

75.13

AR

AR ALIR ACTUAL

90.73

30.00%

27.22



AR ALIR ACTUAL VS TARGET

1.00

20.00%

0.20



AR LANCAR ACTUAL

200.00

30.00%

60.00



AR LANCAR ACTUAL VS TARGET

222.22

20.00%

44.44



Total

223.25

100.00%

223.25

--> it should be

131.86

Grand Total

640.46

200.00%

1280.92




This is the MDX script for Total Point Department:

[Measures].[Bobot Parameter]

* [Measures].[Total Point Parameter]


Can you please help me? Thanks in advance.

Regards,

I have the same issue, have you been able to solve your problem?

|||

Have you tried setting this up use a measure expression instead of a calculated measure?

I think this will make the multiplication happen at the leaf level and then the normal aggregation will kick in.

Otherwise you could try scoping your calculation at the leaf level.

sql

Calculated Measure on SSAS 2005

Dear All,

I have a problem when I made calculation on SSAS 2005. I have two dimensions such as Department and Parameter where 1 Department has several Parameters. Each Parameter has point measure (Total Point Parameter) and bobot measure in percent (Bobot Parameter). The subtotal of Total Point Parameter is sum of Total Point Parameter for parameters in 1 department and the subtotal of Bobot Parameter is sum of Bobot Parameter for parameters in 1 department which the result will be 100%. I want to make a calculated measure named Total Point Department that I can get the result by multiplying Total Point Parameter with Bobot Parameter. But for the subtotal of that calculated measure, the value should be sum of Total Point Department for parameters in 1 Department. I attach the layout so you can have a good understanding to my problem.

Department Parameter Total Point Parameter Bobot Parameter Total Point Department

KREDIT FPD 80.56 25.00% 20.14

NBP 95.49 25.00% 23.87

OVERDUE BPKB 96.17 10.00% 9.62

OVERRIDE SCORING 110.00 10.00% 11.00

POOLING ORDER 35.00 30.00% 10.50

Total 417.21 100.00% 417.21 --> it should be
75.13 AR AR ALIR ACTUAL 90.73 30.00% 27.22

AR ALIR ACTUAL VS TARGET 1.00 20.00% 0.20

AR LANCAR ACTUAL 200.00 30.00% 60.00

AR LANCAR ACTUAL VS TARGET 222.22 20.00% 44.44

Total 223.25 100.00% 223.25 --> it should be
131.86 Grand Total 640.46 200.00% 1280.92


This is the MDX script for Total Point Department:

[Measures].[Bobot Parameter] * [Measures].[Total Point Parameter]


Can you please help me? Thanks in advance.

Regards,

I have the same issue, have you been able to solve your problem?

|||

Have you tried setting this up use a measure expression instead of a calculated measure?

I think this will make the multiplication happen at the leaf level and then the normal aggregation will kick in.

Otherwise you could try scoping your calculation at the leaf level.

Thursday, March 8, 2012

Caching or reusing parameters populated with SqlCommandBuilder.DeriveParameters

Hello,

I have a real heartache with runtime parameter interogation on my DB.
Sure I get the latest and greatest and sure I don't have to type in all those lovely parameter types..but...the hit I take on performance for making no less then 3 DB hits for each SqlAdapter is unreasonable!

So ...I like the idea of maybe calling it once for all my stored procs on application startup...and then maybe saving this in CacheObject.

My problem is that I can't see where you can even serialize a SqlParametersCollection or even for that matter assign it to a Command object. Can you cache a command object ?

LOL

I think I may just have to write some generic routine for creating and populating my command objects based on a key (type) and then use that to fetch my command.Update,
command.Insert and command.

I would like to use the new AsynchBlock to do the fetching of the stored proc parameters and then just pull them from the Cache object...put a file watch so that if the DB's change my params it re-pulls them again.

*nice*....

Then I get the best of both worlds...caching...and no parameter writing...

Ericsp_sproc_columns [[@.procedure_name =] 'name']
[,[@.procedure_owner =] 'owner']
[,[@.procedure_qualifier =] 'qualifier']
[,[@.column_name =] 'column_name']
[,[@.ODBCVer =] 'ODBCVer']

sp_stored_procedures [[@.sp_name =] 'name']
[,[@.sp_owner =] 'owner']
[,[@.sp_qualifier =] 'qualifier']

does that help?|||well yeah that's what I was going to do once I have the params in some cachable state...
I was just wondering if you could fetch the SqlParametersCollection from the Command object...alal IDbCommandParameters

and then cache those dudes...:)

I can manually interogate my hash for the parameters based on type key..."UpdSales", "InsSales","DelSales"...etc..|||those are the system procedures you need to get ALL the procedures from your database, then get their parameters.

Check out the details from books online.|||Duh...

I know that!

The SqlCommandBuilder.DerieveParameters(SqlCommand)

And those parameters have to stored somewhere in command object right?

Ahhh the Parameters which implments the IDbParameterCollection...

So can you fetch or store that Parameters collection...

That is what I"m asking...

I think I will just write the code "AsyncService" to fetch them at Application on start and then store them....I just don't like all those chatty calls ...that's all

Cached Reports

Is it possible to cache a version of a report, meaning say I pass a parameter "CacheReport" which is a boolean. Can I only cache this report when this variable is set to true?I don't believe that's currently a settable option. You can set them to
cache with the first user, on a schedule or have it pull from a snapshot
each time.
"comet61" <comet61@.discussions.microsoft.com> wrote in message
news:C6DEDF65-C480-430B-A94C-968107D1AC6C@.microsoft.com...
> Is it possible to cache a version of a report, meaning say I pass a
> parameter "CacheReport" which is a boolean. Can I only cache this report
> when this variable is set to true?

Saturday, February 25, 2012

C++ oledb templates

Below, you'll see a parameter map and parts of a data class.
It works (that's the good thing). The parameter was, originally, an image
datatype, but unfortunately, I had to make it varbinary(8000) because of
runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
medium). Does anybody have a clue why I cannot just use a SequentialStream
without errors? (ps: Visual C++ 7.1 has even more problems with this when
you use attributes)
(some code has been omitted to shorten...)
BYTE m_PtrStatePar[16];
DBLENGTH m_dwPtrStateLength;
//ISequentialStream *pStream; //does not work
PBYTE m_BLOB;
DBLENGTH m_dwStateLength;
DBSTATUS m_dwStateStatus;
LONG insertptr;
BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(2, insertptr)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
//returns 'you must bind parameters first' error and E_UNEXPECTED
//BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
m_dwStateLength, m_dwStateStatus)
_COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf (m_dwStateLength),0)
END_PARAM_MAP()
};
class CpSessionUpdate1 : public
CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
HRESULT OpenRowset(ATL::CSession ms)
hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
Hi,
I just completed OLEDB project that included BLOB functionality. Everything
works very well (with SQLOLEDB provider and MSSQL2000 database). However, I
can't help you here because I didn't use ATL OLEDB template classes at all:
I used OLEDB interfaces directly. There're some good BLOB-handling samples
in SQL2000 Books Online.
Boris
"Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> Below, you'll see a parameter map and parts of a data class.
> It works (that's the good thing). The parameter was, originally, an image
> datatype, but unfortunately, I had to make it varbinary(8000) because of
> runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> medium). Does anybody have a clue why I cannot just use a SequentialStream
> without errors? (ps: Visual C++ 7.1 has even more problems with this when
> you use attributes)
> (some code has been omitted to shorten...)
> BYTE m_PtrStatePar[16];
> DBLENGTH m_dwPtrStateLength;
> //ISequentialStream *pStream; //does not work
> PBYTE m_BLOB;
> DBLENGTH m_dwStateLength;
> DBSTATUS m_dwStateStatus;
> LONG insertptr;
>
> BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY(2, insertptr)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> //returns 'you must bind parameters first' error and E_UNEXPECTED
> //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
> m_dwStateLength, m_dwStateStatus)
> _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> _SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf (m_dwStateLength),0)
> END_PARAM_MAP()
> };
> class CpSessionUpdate1 : public
> CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
>
> HRESULT OpenRowset(ATL::CSession ms)
> hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
>
>
|||I have a solution, however, it has a problem. If you can help me with the
problem you can use the code. I have written a template OLEDB class to
support reading and writing BLOB data to and from an SQL 2000 database.
This code works perfectly when compiled on VC6.0. Porting to VC7.0 however
has generated a serious problem. When writing to the database all goes well
until my CCommand object begins to destroy itself. When FreeType() is
called in the clean up routine for the BLOB column, the program crashes with
an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
which points to somewhere. (I have no idea where). Thoughts? Help? Some
code is below, as well as a link to a good sample. Let me know if you run
into the same problem.
James
// The following MACRO was required for VC6.0 but was included in VC7.0 The
code is very similar.
#define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset, lengthOffset,
statusOffset) \
if (pBuffer != NULL) \
{ \
CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
} \
else if (pBinding != NULL) \
{ \
DBOBJECT* pObject = NULL; \
ATLTRY(pObject = new DBOBJECT); \
if (pObject == NULL) \
return E_OUTOFMEMORY; \
pObject->dwFlags = flags; \
pObject->iid = IID; \
CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
sizeof(IUnknown*), 0, 0, eParamIO, \
dataOffset, lengthOffset, statusOffset, pObject); \
pBinding++; \
} \
nColumns++;
#ifdef BLOB_ENTRY_LENGTH_STATUS
#undef BLOB_ENTRY_LENGTH_STATUS
#define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length, status)
\
_BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
offsetbuf(length), offsetbuf(status));
#endif
enum
{
HEADER = 1,
CONTENTSIZE,
CONTENT,
NUM_COLUMNS_PLUS_ONE
};
class CdboMessagesAccessor
{
public:
TCHAR m_header[4097];
LONG m_contentSize;
ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
m_messageContentLength;
BEGIN_COLUMN_MAP(CdboMessagesAccessor)
COLUMN_ENTRY(HEADER, m_header)
COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
BLOB_ENTRY_LENGTH_STATUS(CONTENT,
IID_ISequentialStream,
STGM_READ,
m_messageContent,
m_messageContentLength,
m_messageContentStatus)
END_COLUMN_MAP()
DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
SELECT \
header, \
contentSize, \
messageContent, \
FROM dbo.Messages"))
// You may wish to call this function if you are inserting a record and wish
to
// initialize all the fields, if you are not going to explicitly set all of
them.
void ClearRecord()
{
memset(this, 0, sizeof(*this));
m_sentStatus = DBSTATUS_S_ISNULL;
m_receivedStatus = DBSTATUS_S_ISNULL;
}
};
// Write a data element
// CMyISSImp is a wrapper class which has a base class of ISequentialStream
CdboMessages dbo(&m_session);
hr = dbo.Open();
if (SUCCEEDED(hr))
{
dbo.ClearRecord();
// Create the message object and write to the database
COPYSTRING(dbo.m_header, GetHeader());
// The entire block below is needed to write to the messageContent
column
std::string s = GetContent();
try
{
CMyISSImp *pStream = new CMyISSImp(s);
if (pStream)
{
dbo.m_messageContentLength = s.size();
dbo.m_messageContentStatus = DBSTATUS_S_OK;
dbo.m_messageContent = (ISequentialStream*)pStream;
dbo.m_contentSize = s.size();
}
else
{
_com_issue_error(E_OUTOFMEMORY);
}
}
catch(_com_error &e)
{
// Something failed
hr = e.Error();
}
}
if (!Check(hr))
{
dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
}
// Write the data to the database
hr = dbo.Insert();
// Read data from the database
CdboMessages dbo(&m_session);
HRESULT hr = dbo.Open(m_switchID, messageID);
if (Check(hr))
{
hr = dbo.MoveFirst(); // and only...but we won't check, the database
should enforce this
if (Check(hr))
{
std::string content;
if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
dbo.m_messageContent)
{
if (dbo.m_contentSize > 0)
{
content.resize(dbo.m_contentSize);
int pos = 0;
while(1)
{
// Documentation is unclear as to what can happen when we
reach the end of
// a stream. Although it is stated that Read() can return an
error, it doesn't
// indicates what this means about the buffer or the number
of bytes read.
// I have determined that OLEDB seems to return success with
a bytes count < size
// when the end of the stream is encountered. This allows
the loop to exit properly
// If however a future implementation returns an error with
some uninitialized byte
// count this could cause errors. No one implementation of
this function can account
// for all possiblities so I will leave it like this for
now.
static const size = 1024;
char buffer[size];
ULONG read;
dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
// Make sure we don't overflow the buffer
if (content.size() < pos + size)
{
content.resize(content.size() + size);
}
for(int i = 0; i<read; i++)
{
content[pos++] = buffer[i];
}
if (read < size)
{
break;
}
}
content.resize(pos);
}
}
}
}
The basic design for this came from here:
http://support.microsoft.com/?kbid=190958&sd=msdn
"Boris Dynin" <spam@.noplease.com> wrote in message
news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> Hi,
> I just completed OLEDB project that included BLOB functionality.
Everything
> works very well (with SQLOLEDB provider and MSSQL2000 database). However,
I
> can't help you here because I didn't use ATL OLEDB template classes at
all:[vbcol=seagreen]
> I used OLEDB interfaces directly. There're some good BLOB-handling samples
> in SQL2000 Books Online.
> Boris
> "Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
> message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
image[vbcol=seagreen]
SequentialStream[vbcol=seagreen]
when
>
|||What kind of accessor are you using? If you use CDynamicAccessor, you will
have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
table.SetBlobSizeLimit(1024);
table.SetBlobHandling(DBBLOBHANDLING_NOSTREAMS);
This will make all blob bindings by ref.
Joo Paulo Figueira
Embedded MVP
"James Ryan" <__@._jryan@.__icescape.__com> wrote in message
news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
> I have a solution, however, it has a problem. If you can help me with the
> problem you can use the code. I have written a template OLEDB class to
> support reading and writing BLOB data to and from an SQL 2000 database.
> This code works perfectly when compiled on VC6.0. Porting to VC7.0
however
> has generated a serious problem. When writing to the database all goes
well
> until my CCommand object begins to destroy itself. When FreeType() is
> called in the clean up routine for the BLOB column, the program crashes
with
> an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
> which points to somewhere. (I have no idea where). Thoughts? Help?
Some
> code is below, as well as a link to a good sample. Let me know if you
run
> into the same problem.
> James
> // The following MACRO was required for VC6.0 but was included in VC7.0
The
> code is very similar.
>
> #define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset,
lengthOffset,
> statusOffset) \
> if (pBuffer != NULL) \
> { \
> CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
> } \
> else if (pBinding != NULL) \
> { \
> DBOBJECT* pObject = NULL; \
> ATLTRY(pObject = new DBOBJECT); \
> if (pObject == NULL) \
> return E_OUTOFMEMORY; \
> pObject->dwFlags = flags; \
> pObject->iid = IID; \
> CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
> sizeof(IUnknown*), 0, 0, eParamIO, \
> dataOffset, lengthOffset, statusOffset, pObject); \
> pBinding++; \
> } \
> nColumns++;
> #ifdef BLOB_ENTRY_LENGTH_STATUS
> #undef BLOB_ENTRY_LENGTH_STATUS
> #define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length,
status)
> \
> _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
> offsetbuf(length), offsetbuf(status));
> #endif
> enum
> {
> HEADER = 1,
> CONTENTSIZE,
> CONTENT,
> NUM_COLUMNS_PLUS_ONE
> };
> class CdboMessagesAccessor
> {
> public:
> TCHAR m_header[4097];
> LONG m_contentSize;
> ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
> m_messageContentLength;
> BEGIN_COLUMN_MAP(CdboMessagesAccessor)
> COLUMN_ENTRY(HEADER, m_header)
> COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
> BLOB_ENTRY_LENGTH_STATUS(CONTENT,
> IID_ISequentialStream,
> STGM_READ,
> m_messageContent,
> m_messageContentLength,
> m_messageContentStatus)
> END_COLUMN_MAP()
> DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
> SELECT \
> header, \
> contentSize, \
> messageContent, \
> FROM dbo.Messages"))
> // You may wish to call this function if you are inserting a record and
wish
> to
> // initialize all the fields, if you are not going to explicitly set all
of
> them.
> void ClearRecord()
> {
> memset(this, 0, sizeof(*this));
> m_sentStatus = DBSTATUS_S_ISNULL;
> m_receivedStatus = DBSTATUS_S_ISNULL;
> }
> };
>
> // Write a data element
> // CMyISSImp is a wrapper class which has a base class of
ISequentialStream
> CdboMessages dbo(&m_session);
> hr = dbo.Open();
> if (SUCCEEDED(hr))
> {
> dbo.ClearRecord();
> // Create the message object and write to the database
> COPYSTRING(dbo.m_header, GetHeader());
> // The entire block below is needed to write to the messageContent
> column
> std::string s = GetContent();
> try
> {
> CMyISSImp *pStream = new CMyISSImp(s);
> if (pStream)
> {
> dbo.m_messageContentLength = s.size();
> dbo.m_messageContentStatus = DBSTATUS_S_OK;
> dbo.m_messageContent = (ISequentialStream*)pStream;
> dbo.m_contentSize = s.size();
> }
> else
> {
> _com_issue_error(E_OUTOFMEMORY);
> }
> }
> catch(_com_error &e)
> {
> // Something failed
> hr = e.Error();
> }
> }
> if (!Check(hr))
> {
> dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
> }
> // Write the data to the database
> hr = dbo.Insert();
>
> // Read data from the database
> CdboMessages dbo(&m_session);
> HRESULT hr = dbo.Open(m_switchID, messageID);
> if (Check(hr))
> {
> hr = dbo.MoveFirst(); // and only...but we won't check, the database
> should enforce this
> if (Check(hr))
> {
> std::string content;
> if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
> dbo.m_messageContent)
> {
> if (dbo.m_contentSize > 0)
> {
> content.resize(dbo.m_contentSize);
> int pos = 0;
> while(1)
> {
> // Documentation is unclear as to what can happen when we
> reach the end of
> // a stream. Although it is stated that Read() can return
an
> error, it doesn't
> // indicates what this means about the buffer or the
number
> of bytes read.
> // I have determined that OLEDB seems to return success
with
> a bytes count < size
> // when the end of the stream is encountered. This allows
> the loop to exit properly
> // If however a future implementation returns an error
with[vbcol=seagreen]
> some uninitialized byte
> // count this could cause errors. No one implementation of
> this function can account
> // for all possiblities so I will leave it like this for
> now.
> static const size = 1024;
> char buffer[size];
> ULONG read;
> dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
> // Make sure we don't overflow the buffer
> if (content.size() < pos + size)
> {
> content.resize(content.size() + size);
> }
> for(int i = 0; i<read; i++)
> {
> content[pos++] = buffer[i];
> }
> if (read < size)
> {
> break;
> }
> }
> content.resize(pos);
> }
> }
> }
> }
> The basic design for this came from here:
> http://support.microsoft.com/?kbid=190958&sd=msdn
>
> "Boris Dynin" <spam@.noplease.com> wrote in message
> news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> Everything
However,[vbcol=seagreen]
> I
> all:
samples[vbcol=seagreen]
> image
of[vbcol=seagreen]
> SequentialStream
> when
pStream,
>
|||Interesting, however, this class is using the CAccessor template class as I
have defined the database structure specific to this app.
I have managed to determine that my stream object is being released more
times than it is being AddRef'd. I have created an initial reference when I
pass the object to the insert() call. During the insert and the subsequent
object destruction, I see TWO AddRef's by the oledb dll (sqloledb.dll)
followed by THREE releases. At this point the object is destroyed.
However, the template class still has a reference to the object and it tries
to release() as well. This causes the crash. I have "fixed" the problem by
setting the object pointer in the Accessor class to zero after the insert
call so the template class will not try to release it. This hardly sounds
like the proper solution however, at this point I don't know if I am looking
at a bug in OLEDB or some error in my own code.
James
"Joo Paulo Figueira [eMVP]" <joao.figueira@.primeworks.takethisout.pt> wrote
in message news:uQMh5qMTEHA.2480@.TK2MSFTNGP10.phx.gbl...[vbcol=seagreen]
> What kind of accessor are you using? If you use CDynamicAccessor, you will
> have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
> table.SetBlobSizeLimit(1024);
> table.SetBlobHandling(DBBLOBHANDLING_NOSTREAMS);
> This will make all blob bindings by ref.
> --
> Joo Paulo Figueira
> Embedded MVP
> "James Ryan" <__@._jryan@.__icescape.__com> wrote in message
> news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
the[vbcol=seagreen]
> however
> well
> with
pointer[vbcol=seagreen]
> Some
> run
> The
> lengthOffset,
> status)
> wish
> of
> ISequentialStream
we[vbcol=seagreen]
return[vbcol=seagreen]
> an
> number
> with
allows[vbcol=seagreen]
> with
of[vbcol=seagreen]
> However,
> samples
because[vbcol=seagreen]
> of
> pStream,
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf (m_dwStateLength),0)
>

C++ oledb templates

Below, you'll see a parameter map and parts of a data class.
It works (that's the good thing). The parameter was, originally, an image
datatype, but unfortunately, I had to make it varbinary(8000) because of
runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
medium). Does anybody have a clue why I cannot just use a SequentialStream
without errors? (ps: Visual C++ 7.1 has even more problems with this when
you use attributes)
(some code has been omitted to shorten...)
BYTE m_PtrStatePar[16];
DBLENGTH m_dwPtrStateLength;
//ISequentialStream *pStream; //does not work
PBYTE m_BLOB;
DBLENGTH m_dwStateLength;
DBSTATUS m_dwStateStatus;
LONG insertptr;
BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(2, insertptr)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
//returns 'you must bind parameters first' error and E_UNEXPECTED
//BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
m_dwStateLength, m_dwStateStatus)
_COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf(m_dwStateLength),0)
END_PARAM_MAP()
};
class CpSessionUpdate1 : public
CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
HRESULT OpenRowset(ATL::CSession ms)
hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");Hi,
I just completed OLEDB project that included BLOB functionality. Everything
works very well (with SQLOLEDB provider and MSSQL2000 database). However, I
can't help you here because I didn't use ATL OLEDB template classes at all:
I used OLEDB interfaces directly. There're some good BLOB-handling samples
in SQL2000 Books Online.
Boris
"Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> Below, you'll see a parameter map and parts of a data class.
> It works (that's the good thing). The parameter was, originally, an image
> datatype, but unfortunately, I had to make it varbinary(8000) because of
> runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> medium). Does anybody have a clue why I cannot just use a SequentialStream
> without errors? (ps: Visual C++ 7.1 has even more problems with this when
> you use attributes)
> (some code has been omitted to shorten...)
> BYTE m_PtrStatePar[16];
> DBLENGTH m_dwPtrStateLength;
> //ISequentialStream *pStream; //does not work
> PBYTE m_BLOB;
> DBLENGTH m_dwStateLength;
> DBSTATUS m_dwStateStatus;
> LONG insertptr;
>
> BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY(2, insertptr)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> //returns 'you must bind parameters first' error and E_UNEXPECTED
> //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
> m_dwStateLength, m_dwStateStatus)
> _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> _SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf(m_dwStateLength),0)
> END_PARAM_MAP()
> };
> class CpSessionUpdate1 : public
> CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
>
> HRESULT OpenRowset(ATL::CSession ms)
> hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
>
>|||I have a solution, however, it has a problem. If you can help me with the
problem you can use the code. I have written a template OLEDB class to
support reading and writing BLOB data to and from an SQL 2000 database.
This code works perfectly when compiled on VC6.0. Porting to VC7.0 however
has generated a serious problem. When writing to the database all goes well
until my CCommand object begins to destroy itself. When FreeType() is
called in the clean up routine for the BLOB column, the program crashes with
an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
which points to somewhere. (I have no idea where). Thoughts? Help? Some
code is below, as well as a link to a good sample. Let me know if you run
into the same problem.
James
// The following MACRO was required for VC6.0 but was included in VC7.0 The
code is very similar.
#define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset, lengthOffset,
statusOffset) \
if (pBuffer != NULL) \
{ \
CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
} \
else if (pBinding != NULL) \
{ \
DBOBJECT* pObject = NULL; \
ATLTRY(pObject = new DBOBJECT); \
if (pObject == NULL) \
return E_OUTOFMEMORY; \
pObject->dwFlags = flags; \
pObject->iid = IID; \
CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
sizeof(IUnknown*), 0, 0, eParamIO, \
dataOffset, lengthOffset, statusOffset, pObject); \
pBinding++; \
} \
nColumns++;
#ifdef BLOB_ENTRY_LENGTH_STATUS
#undef BLOB_ENTRY_LENGTH_STATUS
#define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length, status)
\
_BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
offsetbuf(length), offsetbuf(status));
#endif
enum
{
HEADER = 1,
CONTENTSIZE,
CONTENT,
NUM_COLUMNS_PLUS_ONE
};
class CdboMessagesAccessor
{
public:
TCHAR m_header[4097];
LONG m_contentSize;
ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
m_messageContentLength;
BEGIN_COLUMN_MAP(CdboMessagesAccessor)
COLUMN_ENTRY(HEADER, m_header)
COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
BLOB_ENTRY_LENGTH_STATUS(CONTENT,
IID_ISequentialStream,
STGM_READ,
m_messageContent,
m_messageContentLength,
m_messageContentStatus)
END_COLUMN_MAP()
DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
SELECT \
header, \
contentSize, \
messageContent, \
FROM dbo.Messages"))
// You may wish to call this function if you are inserting a record and wish
to
// initialize all the fields, if you are not going to explicitly set all of
them.
void ClearRecord()
{
memset(this, 0, sizeof(*this));
m_sentStatus = DBSTATUS_S_ISNULL;
m_receivedStatus = DBSTATUS_S_ISNULL;
}
};
// Write a data element
// CMyISSImp is a wrapper class which has a base class of ISequentialStream
CdboMessages dbo(&m_session);
hr = dbo.Open();
if (SUCCEEDED(hr))
{
dbo.ClearRecord();
// Create the message object and write to the database
COPYSTRING(dbo.m_header, GetHeader());
// The entire block below is needed to write to the messageContent
column
std::string s = GetContent();
try
{
CMyISSImp *pStream = new CMyISSImp(s);
if (pStream)
{
dbo.m_messageContentLength = s.size();
dbo.m_messageContentStatus = DBSTATUS_S_OK;
dbo.m_messageContent = (ISequentialStream*)pStream;
dbo.m_contentSize = s.size();
}
else
{
_com_issue_error(E_OUTOFMEMORY);
}
}
catch(_com_error &e)
{
// Something failed
hr = e.Error();
}
}
if (!Check(hr))
{
dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
}
// Write the data to the database
hr = dbo.Insert();
// Read data from the database
CdboMessages dbo(&m_session);
HRESULT hr = dbo.Open(m_switchID, messageID);
if (Check(hr))
{
hr = dbo.MoveFirst(); // and only...but we won't check, the database
should enforce this
if (Check(hr))
{
std::string content;
if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
dbo.m_messageContent)
{
if (dbo.m_contentSize > 0)
{
content.resize(dbo.m_contentSize);
int pos = 0;
while(1)
{
// Documentation is unclear as to what can happen when we
reach the end of
// a stream. Although it is stated that Read() can return an
error, it doesn't
// indicates what this means about the buffer or the number
of bytes read.
// I have determined that OLEDB seems to return success with
a bytes count < size
// when the end of the stream is encountered. This allows
the loop to exit properly
// If however a future implementation returns an error with
some uninitialized byte
// count this could cause errors. No one implementation of
this function can account
// for all possiblities so I will leave it like this for
now.
static const size = 1024;
char buffer[size];
ULONG read;
dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
// Make sure we don't overflow the buffer
if (content.size() < pos + size)
{
content.resize(content.size() + size);
}
for(int i = 0; i<read; i++)
{
content[pos++] = buffer[i];
}
if (read < size)
{
break;
}
}
content.resize(pos);
}
}
}
}
The basic design for this came from here:
http://support.microsoft.com/?kbid=190958&sd=msdn
"Boris Dynin" <spam@.noplease.com> wrote in message
news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> Hi,
> I just completed OLEDB project that included BLOB functionality.
Everything
> works very well (with SQLOLEDB provider and MSSQL2000 database). However,
I
> can't help you here because I didn't use ATL OLEDB template classes at
all:
> I used OLEDB interfaces directly. There're some good BLOB-handling samples
> in SQL2000 Books Online.
> Boris
> "Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
> message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> > Below, you'll see a parameter map and parts of a data class.
> >
> > It works (that's the good thing). The parameter was, originally, an
image
> > datatype, but unfortunately, I had to make it varbinary(8000) because of
> > runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> > medium). Does anybody have a clue why I cannot just use a
SequentialStream
> > without errors? (ps: Visual C++ 7.1 has even more problems with this
when
> > you use attributes)
> >
> > (some code has been omitted to shorten...)
> >
> > BYTE m_PtrStatePar[16];
> >
> > DBLENGTH m_dwPtrStateLength;
> >
> > //ISequentialStream *pStream; //does not work
> >
> > PBYTE m_BLOB;
> >
> > DBLENGTH m_dwStateLength;
> >
> > DBSTATUS m_dwStateStatus;
> >
> > LONG insertptr;
> >
> >
> >
> > BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
> >
> > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> >
> > COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> >
> > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> >
> > COLUMN_ENTRY(2, insertptr)
> >
> > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> >
> > //returns 'you must bind parameters first' error and E_UNEXPECTED
> >
> > //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
> > m_dwStateLength, m_dwStateStatus)
> >
> > _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> > _SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf(m_dwStateLength),0)
> >
> > END_PARAM_MAP()
> >
> > };
> >
> > class CpSessionUpdate1 : public
> > CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
> >
> >
> >
> > HRESULT OpenRowset(ATL::CSession ms)
> >
> > hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
> >
> >
> >
>|||What kind of accessor are you using? If you use CDynamicAccessor, you will
have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
table.SetBlobSizeLimit(1024);
table.SetBlobHandling(DBBLOBHANDLING_NOSTREAMS);
This will make all blob bindings by ref.
--
João Paulo Figueira
Embedded MVP
"James Ryan" <__@._jryan@.__icescape.__com> wrote in message
news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
> I have a solution, however, it has a problem. If you can help me with the
> problem you can use the code. I have written a template OLEDB class to
> support reading and writing BLOB data to and from an SQL 2000 database.
> This code works perfectly when compiled on VC6.0. Porting to VC7.0
however
> has generated a serious problem. When writing to the database all goes
well
> until my CCommand object begins to destroy itself. When FreeType() is
> called in the clean up routine for the BLOB column, the program crashes
with
> an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
> which points to somewhere. (I have no idea where). Thoughts? Help?
Some
> code is below, as well as a link to a good sample. Let me know if you
run
> into the same problem.
> James
> // The following MACRO was required for VC6.0 but was included in VC7.0
The
> code is very similar.
>
> #define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset,
lengthOffset,
> statusOffset) \
> if (pBuffer != NULL) \
> { \
> CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
> } \
> else if (pBinding != NULL) \
> { \
> DBOBJECT* pObject = NULL; \
> ATLTRY(pObject = new DBOBJECT); \
> if (pObject == NULL) \
> return E_OUTOFMEMORY; \
> pObject->dwFlags = flags; \
> pObject->iid = IID; \
> CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
> sizeof(IUnknown*), 0, 0, eParamIO, \
> dataOffset, lengthOffset, statusOffset, pObject); \
> pBinding++; \
> } \
> nColumns++;
> #ifdef BLOB_ENTRY_LENGTH_STATUS
> #undef BLOB_ENTRY_LENGTH_STATUS
> #define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length,
status)
> \
> _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
> offsetbuf(length), offsetbuf(status));
> #endif
> enum
> {
> HEADER = 1,
> CONTENTSIZE,
> CONTENT,
> NUM_COLUMNS_PLUS_ONE
> };
> class CdboMessagesAccessor
> {
> public:
> TCHAR m_header[4097];
> LONG m_contentSize;
> ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
> m_messageContentLength;
> BEGIN_COLUMN_MAP(CdboMessagesAccessor)
> COLUMN_ENTRY(HEADER, m_header)
> COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
> BLOB_ENTRY_LENGTH_STATUS(CONTENT,
> IID_ISequentialStream,
> STGM_READ,
> m_messageContent,
> m_messageContentLength,
> m_messageContentStatus)
> END_COLUMN_MAP()
> DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
> SELECT \
> header, \
> contentSize, \
> messageContent, \
> FROM dbo.Messages"))
> // You may wish to call this function if you are inserting a record and
wish
> to
> // initialize all the fields, if you are not going to explicitly set all
of
> them.
> void ClearRecord()
> {
> memset(this, 0, sizeof(*this));
> m_sentStatus = DBSTATUS_S_ISNULL;
> m_receivedStatus = DBSTATUS_S_ISNULL;
> }
> };
>
> // Write a data element
> // CMyISSImp is a wrapper class which has a base class of
ISequentialStream
> CdboMessages dbo(&m_session);
> hr = dbo.Open();
> if (SUCCEEDED(hr))
> {
> dbo.ClearRecord();
> // Create the message object and write to the database
> COPYSTRING(dbo.m_header, GetHeader());
> // The entire block below is needed to write to the messageContent
> column
> std::string s = GetContent();
> try
> {
> CMyISSImp *pStream = new CMyISSImp(s);
> if (pStream)
> {
> dbo.m_messageContentLength = s.size();
> dbo.m_messageContentStatus = DBSTATUS_S_OK;
> dbo.m_messageContent = (ISequentialStream*)pStream;
> dbo.m_contentSize = s.size();
> }
> else
> {
> _com_issue_error(E_OUTOFMEMORY);
> }
> }
> catch(_com_error &e)
> {
> // Something failed
> hr = e.Error();
> }
> }
> if (!Check(hr))
> {
> dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
> }
> // Write the data to the database
> hr = dbo.Insert();
>
> // Read data from the database
> CdboMessages dbo(&m_session);
> HRESULT hr = dbo.Open(m_switchID, messageID);
> if (Check(hr))
> {
> hr = dbo.MoveFirst(); // and only...but we won't check, the database
> should enforce this
> if (Check(hr))
> {
> std::string content;
> if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
> dbo.m_messageContent)
> {
> if (dbo.m_contentSize > 0)
> {
> content.resize(dbo.m_contentSize);
> int pos = 0;
> while(1)
> {
> // Documentation is unclear as to what can happen when we
> reach the end of
> // a stream. Although it is stated that Read() can return
an
> error, it doesn't
> // indicates what this means about the buffer or the
number
> of bytes read.
> // I have determined that OLEDB seems to return success
with
> a bytes count < size
> // when the end of the stream is encountered. This allows
> the loop to exit properly
> // If however a future implementation returns an error
with
> some uninitialized byte
> // count this could cause errors. No one implementation of
> this function can account
> // for all possiblities so I will leave it like this for
> now.
> static const size = 1024;
> char buffer[size];
> ULONG read;
> dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
> // Make sure we don't overflow the buffer
> if (content.size() < pos + size)
> {
> content.resize(content.size() + size);
> }
> for(int i = 0; i<read; i++)
> {
> content[pos++] = buffer[i];
> }
> if (read < size)
> {
> break;
> }
> }
> content.resize(pos);
> }
> }
> }
> }
> The basic design for this came from here:
> http://support.microsoft.com/?kbid=190958&sd=msdn
>
> "Boris Dynin" <spam@.noplease.com> wrote in message
> news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> > Hi,
> >
> > I just completed OLEDB project that included BLOB functionality.
> Everything
> > works very well (with SQLOLEDB provider and MSSQL2000 database).
However,
> I
> > can't help you here because I didn't use ATL OLEDB template classes at
> all:
> > I used OLEDB interfaces directly. There're some good BLOB-handling
samples
> > in SQL2000 Books Online.
> >
> > Boris
> >
> > "Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
> > message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> > > Below, you'll see a parameter map and parts of a data class.
> > >
> > > It works (that's the good thing). The parameter was, originally, an
> image
> > > datatype, but unfortunately, I had to make it varbinary(8000) because
of
> > > runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> > > medium). Does anybody have a clue why I cannot just use a
> SequentialStream
> > > without errors? (ps: Visual C++ 7.1 has even more problems with this
> when
> > > you use attributes)
> > >
> > > (some code has been omitted to shorten...)
> > >
> > > BYTE m_PtrStatePar[16];
> > >
> > > DBLENGTH m_dwPtrStateLength;
> > >
> > > //ISequentialStream *pStream; //does not work
> > >
> > > PBYTE m_BLOB;
> > >
> > > DBLENGTH m_dwStateLength;
> > >
> > > DBSTATUS m_dwStateStatus;
> > >
> > > LONG insertptr;
> > >
> > >
> > >
> > > BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
> > >
> > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > >
> > > COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> > >
> > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > >
> > > COLUMN_ENTRY(2, insertptr)
> > >
> > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > >
> > > //returns 'you must bind parameters first' error and E_UNEXPECTED
> > >
> > > //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ,
pStream,
> > > m_dwStateLength, m_dwStateStatus)
> > >
> > > _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> > > _SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf(m_dwStateLength),0)
> > >
> > > END_PARAM_MAP()
> > >
> > > };
> > >
> > > class CpSessionUpdate1 : public
> > > CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
> > >
> > >
> > >
> > > HRESULT OpenRowset(ATL::CSession ms)
> > >
> > > hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
> > >
> > >
> > >
> >
> >
>|||Interesting, however, this class is using the CAccessor template class as I
have defined the database structure specific to this app.
I have managed to determine that my stream object is being released more
times than it is being AddRef'd. I have created an initial reference when I
pass the object to the insert() call. During the insert and the subsequent
object destruction, I see TWO AddRef's by the oledb dll (sqloledb.dll)
followed by THREE releases. At this point the object is destroyed.
However, the template class still has a reference to the object and it tries
to release() as well. This causes the crash. I have "fixed" the problem by
setting the object pointer in the Accessor class to zero after the insert
call so the template class will not try to release it. This hardly sounds
like the proper solution however, at this point I don't know if I am looking
at a bug in OLEDB or some error in my own code.
James
"João Paulo Figueira [eMVP]" <joao.figueira@.primeworks.takethisout.pt> wrote
in message news:uQMh5qMTEHA.2480@.TK2MSFTNGP10.phx.gbl...
> What kind of accessor are you using? If you use CDynamicAccessor, you will
> have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
> table.SetBlobSizeLimit(1024);
> table.SetBlobHandling(DBBLOBHANDLING_NOSTREAMS);
> This will make all blob bindings by ref.
> --
> João Paulo Figueira
> Embedded MVP
> "James Ryan" <__@._jryan@.__icescape.__com> wrote in message
> news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
> >
> > I have a solution, however, it has a problem. If you can help me with
the
> > problem you can use the code. I have written a template OLEDB class to
> > support reading and writing BLOB data to and from an SQL 2000 database.
> > This code works perfectly when compiled on VC6.0. Porting to VC7.0
> however
> > has generated a serious problem. When writing to the database all goes
> well
> > until my CCommand object begins to destroy itself. When FreeType() is
> > called in the clean up routine for the BLOB column, the program crashes
> with
> > an access violation. FreeType() is trying to clean up an IUNKNOWN
pointer
> > which points to somewhere. (I have no idea where). Thoughts? Help?
> Some
> > code is below, as well as a link to a good sample. Let me know if you
> run
> > into the same problem.
> >
> > James
> >
> > // The following MACRO was required for VC6.0 but was included in VC7.0
> The
> > code is very similar.
> >
> >
> > #define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset,
> lengthOffset,
> > statusOffset) \
> > if (pBuffer != NULL) \
> > { \
> > CAccessorBase::FreeType(DBTYPE_IUNKNOWN, pBuffer + dataOffset); \
> > } \
> > else if (pBinding != NULL) \
> > { \
> > DBOBJECT* pObject = NULL; \
> > ATLTRY(pObject = new DBOBJECT); \
> > if (pObject == NULL) \
> > return E_OUTOFMEMORY; \
> > pObject->dwFlags = flags; \
> > pObject->iid = IID; \
> > CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
> > sizeof(IUnknown*), 0, 0, eParamIO, \
> > dataOffset, lengthOffset, statusOffset, pObject); \
> > pBinding++; \
> > } \
> > nColumns++;
> >
> > #ifdef BLOB_ENTRY_LENGTH_STATUS
> > #undef BLOB_ENTRY_LENGTH_STATUS
> > #define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length,
> status)
> > \
> > _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
> > offsetbuf(length), offsetbuf(status));
> > #endif
> > enum
> > {
> > HEADER = 1,
> > CONTENTSIZE,
> > CONTENT,
> > NUM_COLUMNS_PLUS_ONE
> > };
> >
> > class CdboMessagesAccessor
> > {
> > public:
> > TCHAR m_header[4097];
> > LONG m_contentSize;
> > ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
> > m_messageContentLength;
> >
> > BEGIN_COLUMN_MAP(CdboMessagesAccessor)
> > COLUMN_ENTRY(HEADER, m_header)
> > COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
> > BLOB_ENTRY_LENGTH_STATUS(CONTENT,
> >
> > IID_ISequentialStream,
> > STGM_READ,
> >
> > m_messageContent,
> >
> > m_messageContentLength,
> >
> > m_messageContentStatus)
> > END_COLUMN_MAP()
> >
> > DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
> > SELECT \
> > header, \
> > contentSize, \
> > messageContent, \
> > FROM dbo.Messages"))
> >
> > // You may wish to call this function if you are inserting a record and
> wish
> > to
> > // initialize all the fields, if you are not going to explicitly set all
> of
> > them.
> > void ClearRecord()
> > {
> > memset(this, 0, sizeof(*this));
> >
> > m_sentStatus = DBSTATUS_S_ISNULL;
> > m_receivedStatus = DBSTATUS_S_ISNULL;
> > }
> > };
> >
> >
> > // Write a data element
> > // CMyISSImp is a wrapper class which has a base class of
> ISequentialStream
> >
> > CdboMessages dbo(&m_session);
> > hr = dbo.Open();
> > if (SUCCEEDED(hr))
> > {
> > dbo.ClearRecord();
> > // Create the message object and write to the database
> >
> > COPYSTRING(dbo.m_header, GetHeader());
> >
> > // The entire block below is needed to write to the messageContent
> > column
> > std::string s = GetContent();
> > try
> > {
> > CMyISSImp *pStream = new CMyISSImp(s);
> > if (pStream)
> > {
> > dbo.m_messageContentLength = s.size();
> > dbo.m_messageContentStatus = DBSTATUS_S_OK;
> > dbo.m_messageContent = (ISequentialStream*)pStream;
> >
> > dbo.m_contentSize = s.size();
> > }
> > else
> > {
> > _com_issue_error(E_OUTOFMEMORY);
> > }
> > }
> > catch(_com_error &e)
> > {
> > // Something failed
> > hr = e.Error();
> > }
> > }
> > if (!Check(hr))
> > {
> > dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
> > }
> >
> > // Write the data to the database
> > hr = dbo.Insert();
> >
> >
> > // Read data from the database
> > CdboMessages dbo(&m_session);
> > HRESULT hr = dbo.Open(m_switchID, messageID);
> > if (Check(hr))
> > {
> > hr = dbo.MoveFirst(); // and only...but we won't check, the database
> > should enforce this
> > if (Check(hr))
> > {
> > std::string content;
> > if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
> > dbo.m_messageContent)
> > {
> > if (dbo.m_contentSize > 0)
> > {
> > content.resize(dbo.m_contentSize);
> > int pos = 0;
> > while(1)
> > {
> > // Documentation is unclear as to what can happen when
we
> > reach the end of
> > // a stream. Although it is stated that Read() can
return
> an
> > error, it doesn't
> > // indicates what this means about the buffer or the
> number
> > of bytes read.
> > // I have determined that OLEDB seems to return success
> with
> > a bytes count < size
> > // when the end of the stream is encountered. This
allows
> > the loop to exit properly
> > // If however a future implementation returns an error
> with
> > some uninitialized byte
> > // count this could cause errors. No one implementation
of
> > this function can account
> > // for all possiblities so I will leave it like this for
> > now.
> > static const size = 1024;
> > char buffer[size];
> > ULONG read;
> > dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
> > // Make sure we don't overflow the buffer
> > if (content.size() < pos + size)
> > {
> > content.resize(content.size() + size);
> > }
> > for(int i = 0; i<read; i++)
> > {
> > content[pos++] = buffer[i];
> > }
> > if (read < size)
> > {
> > break;
> > }
> > }
> > content.resize(pos);
> > }
> > }
> > }
> > }
> >
> > The basic design for this came from here:
> > http://support.microsoft.com/?kbid=190958&sd=msdn
> >
> >
> > "Boris Dynin" <spam@.noplease.com> wrote in message
> > news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> > > Hi,
> > >
> > > I just completed OLEDB project that included BLOB functionality.
> > Everything
> > > works very well (with SQLOLEDB provider and MSSQL2000 database).
> However,
> > I
> > > can't help you here because I didn't use ATL OLEDB template classes at
> > all:
> > > I used OLEDB interfaces directly. There're some good BLOB-handling
> samples
> > > in SQL2000 Books Online.
> > >
> > > Boris
> > >
> > > "Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
> > > message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> > > > Below, you'll see a parameter map and parts of a data class.
> > > >
> > > > It works (that's the good thing). The parameter was, originally, an
> > image
> > > > datatype, but unfortunately, I had to make it varbinary(8000)
because
> of
> > > > runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> > > > medium). Does anybody have a clue why I cannot just use a
> > SequentialStream
> > > > without errors? (ps: Visual C++ 7.1 has even more problems with this
> > when
> > > > you use attributes)
> > > >
> > > > (some code has been omitted to shorten...)
> > > >
> > > > BYTE m_PtrStatePar[16];
> > > >
> > > > DBLENGTH m_dwPtrStateLength;
> > > >
> > > > //ISequentialStream *pStream; //does not work
> > > >
> > > > PBYTE m_BLOB;
> > > >
> > > > DBLENGTH m_dwStateLength;
> > > >
> > > > DBSTATUS m_dwStateStatus;
> > > >
> > > > LONG insertptr;
> > > >
> > > >
> > > >
> > > > BEGIN_PARAM_MAP(CpSessionUpdate1Accessor)
> > > >
> > > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > > >
> > > > COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> > > >
> > > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > > >
> > > > COLUMN_ENTRY(2, insertptr)
> > > >
> > > > SET_PARAM_TYPE(DBPARAMIO_INPUT)
> > > >
> > > > //returns 'you must bind parameters first' error and E_UNEXPECTED
> > > >
> > > > //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ,
> pStream,
> > > > m_dwStateLength, m_dwStateStatus)
> > > >
> > > > _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> > > >
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB),offsetbuf(m_dwStateLength),0)
> > > >
> > > > END_PARAM_MAP()
> > > >
> > > > };
> > > >
> > > > class CpSessionUpdate1 : public
> > > > CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
> > > >
> > > >
> > > >
> > > > HRESULT OpenRowset(ATL::CSession ms)
> > > >
> > > > hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
> > > >
> > > >
> > > >
> > >
> > >
> >
> >
>

C++ oledb templates

Below, you'll see a parameter map and parts of a data class.
It works (that's the good thing). The parameter was, originally, an image
datatype, but unfortunately, I had to make it varbinary(8000) because of
runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
medium). Does anybody have a clue why I cannot just use a SequentialStream
without errors? (ps: Visual C++ 7.1 has even more problems with this when
you use attributes)
(some code has been omitted to shorten...)
BYTE m_PtrStatePar[16];
DBLENGTH m_dwPtrStateLength;
//ISequentialStream *pStream; //does not work
PBYTE m_BLOB;
DBLENGTH m_dwStateLength;
DBSTATUS m_dwStateStatus;
LONG insertptr;
BEGIN_PARAM_MAP(CpSessionUpdate1Accessor
)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
COLUMN_ENTRY(2, insertptr)
SET_PARAM_TYPE(DBPARAMIO_INPUT)
//returns 'you must bind parameters first' error and E_UNEXPECTED
//BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
m_dwStateLength, m_dwStateStatus)
_COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB)
,offsetbuf(m_dwStateLength),0)
END_PARAM_MAP()
};
class CpSessionUpdate1 : public
CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
HRESULT OpenRowset(ATL::CSession ms)
hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");Hi,
I just completed OLEDB project that included BLOB functionality. Everything
works very well (with SQLOLEDB provider and MSSQL2000 database). However, I
can't help you here because I didn't use ATL OLEDB template classes at all:
I used OLEDB interfaces directly. There're some good BLOB-handling samples
in SQL2000 Books Online.
Boris
"Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
> Below, you'll see a parameter map and parts of a data class.
> It works (that's the good thing). The parameter was, originally, an image
> datatype, but unfortunately, I had to make it varbinary(8000) because of
> runtime oledb errors (I have oledb 2.8 and use SQL 2000 as a storage
> medium). Does anybody have a clue why I cannot just use a SequentialStream
> without errors? (ps: Visual C++ 7.1 has even more problems with this when
> you use attributes)
> (some code has been omitted to shorten...)
> BYTE m_PtrStatePar[16];
> DBLENGTH m_dwPtrStateLength;
> //ISequentialStream *pStream; //does not work
> PBYTE m_BLOB;
> DBLENGTH m_dwStateLength;
> DBSTATUS m_dwStateStatus;
> LONG insertptr;
>
> BEGIN_PARAM_MAP(CpSessionUpdate1Accessor
)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY_LENGTH(1, m_PtrStatePar, m_dwPtrStateLength)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> COLUMN_ENTRY(2, insertptr)
> SET_PARAM_TYPE(DBPARAMIO_INPUT)
> //returns 'you must bind parameters first' error and E_UNEXPECTED
> //BLOB_ENTRY_LENGTH_STATUS(3, IID_ISequentialStream, STGM_READ, pStream,
> m_dwStateLength, m_dwStateStatus)
> _COLUMN_ENTRY_CODE(3, DBTYPE_BYTES | DBTYPE_BYREF,
> _SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB)
,offsetbuf(m_dwStateLength),0)
> END_PARAM_MAP()
> };
> class CpSessionUpdate1 : public
> CCommand<CAccessor<CpSessionUpdate1Accessor>, CNoRowset >
>
> HRESULT OpenRowset(ATL::CSession ms)
> hr = Open(ms, L"UPDATETEXT mytable.myBLOB ? ? NULL ?");
>
>|||I have a solution, however, it has a problem. If you can help me with the
problem you can use the code. I have written a template OLEDB class to
support reading and writing BLOB data to and from an SQL 2000 database.
This code works perfectly when compiled on VC6.0. Porting to VC7.0 however
has generated a serious problem. When writing to the database all goes well
until my CCommand object begins to destroy itself. When FreeType() is
called in the clean up routine for the BLOB column, the program crashes with
an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
which points to somewhere. (I have no idea where). Thoughts? Help? Some
code is below, as well as a link to a good sample. Let me know if you run
into the same problem.
James
// The following MACRO was required for VC6.0 but was included in VC7.0 The
code is very similar.
#define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset, lengthOffset,
statusOffset) \
if (pBuffer != NULL) \
{ \
CAccessorBase::FreeType(DBTYPE_IUNKNOWN,
pBuffer + dataOffset); \
} \
else if (pBinding != NULL) \
{ \
DBOBJECT* pObject = NULL; \
ATLTRY(pObject = new DBOBJECT); \
if (pObject == NULL) \
return E_OUTOFMEMORY; \
pObject->dwFlags = flags; \
pObject->iid = IID; \
CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
sizeof(IUnknown*), 0, 0, eParamIO, \
dataOffset, lengthOffset, statusOffset, pObject); \
pBinding++; \
} \
nColumns++;
#ifdef BLOB_ENTRY_LENGTH_STATUS
#undef BLOB_ENTRY_LENGTH_STATUS
#define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length, status)
\
_BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
offsetbuf(length), offsetbuf(status));
#endif
enum
{
HEADER = 1,
CONTENTSIZE,
CONTENT,
NUM_COLUMNS_PLUS_ONE
};
class CdboMessagesAccessor
{
public:
TCHAR m_header[4097];
LONG m_contentSize;
ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
m_messageContentLength;
BEGIN_COLUMN_MAP(CdboMessagesAccessor)
COLUMN_ENTRY(HEADER, m_header)
COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
BLOB_ENTRY_LENGTH_STATUS(CONTENT,
IID_ISequentialStream,
STGM_READ,
m_messageContent,
m_messageContentLength,
m_messageContentStatus)
END_COLUMN_MAP()
DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
SELECT \
header, \
contentSize, \
messageContent, \
FROM dbo.Messages"))
// You may wish to call this function if you are inserting a record and wish
to
// initialize all the fields, if you are not going to explicitly set all of
them.
void ClearRecord()
{
memset(this, 0, sizeof(*this));
m_sentStatus = DBSTATUS_S_ISNULL;
m_receivedStatus = DBSTATUS_S_ISNULL;
}
};
// Write a data element
// CMyISSImp is a wrapper class which has a base class of ISequentialStream
CdboMessages dbo(&m_session);
hr = dbo.Open();
if (SUCCEEDED(hr))
{
dbo.ClearRecord();
// Create the message object and write to the database
COPYSTRING(dbo.m_header, GetHeader());
// The entire block below is needed to write to the messageContent
column
std::string s = GetContent();
try
{
CMyISSImp *pStream = new CMyISSImp(s);
if (pStream)
{
dbo.m_messageContentLength = s.size();
dbo.m_messageContentStatus = DBSTATUS_S_OK;
dbo.m_messageContent = (ISequentialStream*)pStream;
dbo.m_contentSize = s.size();
}
else
{
_com_issue_error(E_OUTOFMEMORY);
}
}
catch(_com_error &e)
{
// Something failed
hr = e.Error();
}
}
if (!Check(hr))
{
dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
}
// Write the data to the database
hr = dbo.Insert();
// Read data from the database
CdboMessages dbo(&m_session);
HRESULT hr = dbo.Open(m_switchID, messageID);
if (Check(hr))
{
hr = dbo.MoveFirst(); // and only...but we won't check, the database
should enforce this
if (Check(hr))
{
std::string content;
if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
dbo.m_messageContent)
{
if (dbo.m_contentSize > 0)
{
content.resize(dbo.m_contentSize);
int pos = 0;
while(1)
{
// Documentation is unclear as to what can happen when we
reach the end of
// a stream. Although it is stated that Read() can return an
error, it doesn't
// indicates what this means about the buffer or the number
of bytes read.
// I have determined that OLEDB seems to return success with
a bytes count < size
// when the end of the stream is encountered. This allows
the loop to exit properly
// If however a future implementation returns an error with
some uninitialized byte
// count this could cause errors. No one implementation of
this function can account
// for all possiblities so I will leave it like this for
now.
static const size = 1024;
char buffer[size];
ULONG read;
dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
// Make sure we don't overflow the buffer
if (content.size() < pos + size)
{
content.resize(content.size() + size);
}
for(int i = 0; i<read; i++)
{
content[pos++] = buffer[i];
}
if (read < size)
{
break;
}
}
content.resize(pos);
}
}
}
}
The basic design for this came from here:
http://support.microsoft.com/?kbid=190958&sd=msdn
"Boris Dynin" <spam@.noplease.com> wrote in message
news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> Hi,
> I just completed OLEDB project that included BLOB functionality.
Everything
> works very well (with SQLOLEDB provider and MSSQL2000 database). However,
I
> can't help you here because I didn't use ATL OLEDB template classes at
all:
> I used OLEDB interfaces directly. There're some good BLOB-handling samples
> in SQL2000 Books Online.
> Boris
> "Egbert Nierop (MVP for IIS)" <egbert_nierop@.nospam.invalid> wrote in
> message news:%23jSkVkVIEHA.3248@.TK2MSFTNGP12.phx.gbl...
image[vbcol=seagreen]
SequentialStream[vbcol=seagreen]
when[vbcol=seagreen]
>|||What kind of accessor are you using? If you use CDynamicAccessor, you will
have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
table.SetBlobSizeLimit(1024);
table. SetBlobHandling(DBBLOBHANDLING_NOSTREAMS
);
This will make all blob bindings by ref.
Joo Paulo Figueira
Embedded MVP
"James Ryan" <__@._jryan@.__icescape.__com> wrote in message
news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
> I have a solution, however, it has a problem. If you can help me with the
> problem you can use the code. I have written a template OLEDB class to
> support reading and writing BLOB data to and from an SQL 2000 database.
> This code works perfectly when compiled on VC6.0. Porting to VC7.0
however
> has generated a serious problem. When writing to the database all goes
well
> until my CCommand object begins to destroy itself. When FreeType() is
> called in the clean up routine for the BLOB column, the program crashes
with
> an access violation. FreeType() is trying to clean up an IUNKNOWN pointer
> which points to somewhere. (I have no idea where). Thoughts? Help?
Some
> code is below, as well as a link to a good sample. Let me know if you
run
> into the same problem.
> James
> // The following MACRO was required for VC6.0 but was included in VC7.0
The
> code is very similar.
>
> #define _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, dataOffset,
lengthOffset,
> statusOffset) \
> if (pBuffer != NULL) \
> { \
> CAccessorBase::FreeType(DBTYPE_IUNKNOWN,
pBuffer + dataOffset); \
> } \
> else if (pBinding != NULL) \
> { \
> DBOBJECT* pObject = NULL; \
> ATLTRY(pObject = new DBOBJECT); \
> if (pObject == NULL) \
> return E_OUTOFMEMORY; \
> pObject->dwFlags = flags; \
> pObject->iid = IID; \
> CAccessorBase::Bind(pBinding, nOrdinal, DBTYPE_IUNKNOWN,
> sizeof(IUnknown*), 0, 0, eParamIO, \
> dataOffset, lengthOffset, statusOffset, pObject); \
> pBinding++; \
> } \
> nColumns++;
> #ifdef BLOB_ENTRY_LENGTH_STATUS
> #undef BLOB_ENTRY_LENGTH_STATUS
> #define BLOB_ENTRY_LENGTH_STATUS(nOrdinal, IID, flags, data, length,
status)
> \
> _BLOB_ENTRY_CODE_EX(nOrdinal, IID, flags, offsetbuf(data),
> offsetbuf(length), offsetbuf(status));
> #endif
> enum
> {
> HEADER = 1,
> CONTENTSIZE,
> CONTENT,
> NUM_COLUMNS_PLUS_ONE
> };
> class CdboMessagesAccessor
> {
> public:
> TCHAR m_header[4097];
> LONG m_contentSize;
> ISequentialStream* m_messageContent; ULONG m_messageContentStatus; ULONG
> m_messageContentLength;
> BEGIN_COLUMN_MAP(CdboMessagesAccessor)
> COLUMN_ENTRY(HEADER, m_header)
> COLUMN_ENTRY(CONTENTSIZE, m_contentSize)
> BLOB_ENTRY_LENGTH_STATUS(CONTENT,
> IID_ISequentialStream,
> STGM_READ,
> m_messageContent,
> m_messageContentLength,
> m_messageContentStatus)
> END_COLUMN_MAP()
> DEFINE_COMMAND(CdboMessagesAccessor, _T(" \
> SELECT \
> header, \
> contentSize, \
> messageContent, \
> FROM dbo.Messages"))
> // You may wish to call this function if you are inserting a record and
wish
> to
> // initialize all the fields, if you are not going to explicitly set all
of
> them.
> void ClearRecord()
> {
> memset(this, 0, sizeof(*this));
> m_sentStatus = DBSTATUS_S_ISNULL;
> m_receivedStatus = DBSTATUS_S_ISNULL;
> }
> };
>
> // Write a data element
> // CMyISSImp is a wrapper class which has a base class of
ISequentialStream
> CdboMessages dbo(&m_session);
> hr = dbo.Open();
> if (SUCCEEDED(hr))
> {
> dbo.ClearRecord();
> // Create the message object and write to the database
> COPYSTRING(dbo.m_header, GetHeader());
> // The entire block below is needed to write to the messageContent
> column
> std::string s = GetContent();
> try
> {
> CMyISSImp *pStream = new CMyISSImp(s);
> if (pStream)
> {
> dbo.m_messageContentLength = s.size();
> dbo.m_messageContentStatus = DBSTATUS_S_OK;
> dbo.m_messageContent = (ISequentialStream*)pStream;
> dbo.m_contentSize = s.size();
> }
> else
> {
> _com_issue_error(E_OUTOFMEMORY);
> }
> }
> catch(_com_error &e)
> {
> // Something failed
> hr = e.Error();
> }
> }
> if (!Check(hr))
> {
> dbo.m_messageContentStatus = DBSTATUS_S_ISNULL;
> }
> // Write the data to the database
> hr = dbo.Insert();
>
> // Read data from the database
> CdboMessages dbo(&m_session);
> HRESULT hr = dbo.Open(m_switchID, messageID);
> if (Check(hr))
> {
> hr = dbo.MoveFirst(); // and only...but we won't check, the database
> should enforce this
> if (Check(hr))
> {
> std::string content;
> if (dbo.m_messageContentStatus == DBSTATUS_S_OK &&
> dbo.m_messageContent)
> {
> if (dbo.m_contentSize > 0)
> {
> content.resize(dbo.m_contentSize);
> int pos = 0;
> while(1)
> {
> // Documentation is unclear as to what can happen when we
> reach the end of
> // a stream. Although it is stated that Read() can return
an
> error, it doesn't
> // indicates what this means about the buffer or the
number
> of bytes read.
> // I have determined that OLEDB seems to return success
with
> a bytes count < size
> // when the end of the stream is encountered. This allows
> the loop to exit properly
> // If however a future implementation returns an error
with
> some uninitialized byte
> // count this could cause errors. No one implementation of
> this function can account
> // for all possiblities so I will leave it like this for
> now.
> static const size = 1024;
> char buffer[size];
> ULONG read;
> dbo.m_messageContent->Read((LPVOID)buffer, size, &read);
> // Make sure we don't overflow the buffer
> if (content.size() < pos + size)
> {
> content.resize(content.size() + size);
> }
> for(int i = 0; i<read; i++)
> {
> content[pos++] = buffer[i];
> }
> if (read < size)
> {
> break;
> }
> }
> content.resize(pos);
> }
> }
> }
> }
> The basic design for this came from here:
> http://support.microsoft.com/?kbid=190958&sd=msdn
>
> "Boris Dynin" <spam@.noplease.com> wrote in message
> news:OK7q$7pJEHA.752@.tk2msftngp13.phx.gbl...
> Everything
However,[vbcol=seagreen]
> I
> all:
samples[vbcol=seagreen]
> image
of[vbcol=seagreen]
> SequentialStream
> when
pStream,[vbcol=seagreen]
>|||Interesting, however, this class is using the CAccessor template class as I
have defined the database structure specific to this app.
I have managed to determine that my stream object is being released more
times than it is being AddRef'd. I have created an initial reference when I
pass the object to the insert() call. During the insert and the subsequent
object destruction, I see TWO AddRef's by the oledb dll (sqloledb.dll)
followed by THREE releases. At this point the object is destroyed.
However, the template class still has a reference to the object and it tries
to release() as well. This causes the crash. I have "fixed" the problem by
setting the object pointer in the Accessor class to zero after the insert
call so the template class will not try to release it. This hardly sounds
like the proper solution however, at this point I don't know if I am looking
at a bug in OLEDB or some error in my own code.
James
"Joo Paulo Figueira [eMVP]" <joao.figueira@.primeworks.takethisout.pt> w
rote
in message news:uQMh5qMTEHA.2480@.TK2MSFTNGP10.phx.gbl...
> What kind of accessor are you using? If you use CDynamicAccessor, you will
> have to call SetBlobHandling and SetBlobSizeLimit (new in 7.0). I'm using
> table.SetBlobSizeLimit(1024);
> table. SetBlobHandling(DBBLOBHANDLING_NOSTREAMS
);
> This will make all blob bindings by ref.
> --
> Joo Paulo Figueira
> Embedded MVP
> "James Ryan" <__@._jryan@.__icescape.__com> wrote in message
> news:%235AFa3KTEHA.1544@.TK2MSFTNGP09.phx.gbl...
the[vbcol=seagreen]
> however
> well
> with
pointer[vbcol=seagreen]
> Some
> run
> The
> lengthOffset,
> status)
> wish
> of
> ISequentialStream
we[vbcol=seagreen]
return[vbcol=seagreen]
> an
> number
> with
allows[vbcol=seagreen]
> with
of[vbcol=seagreen]
> However,
> samples
because[vbcol=seagreen]
> of
> pStream,
_SIZE_TYPE(m_BLOB),0,0,offsetbuf(m_BLOB)
,offsetbuf(m_dwStateLength),0)[vbcol=sea
green]
>

Friday, February 24, 2012

C# Command Timestamp Input Parameter

I have a stored proc that inserts a customer and it expects a timestamp input parameter. I dont know what a timestamp datatype is for sql 2005 and Ive tried to parse all sorts of data types but the proc errors out saying it needs "Byte[]" which Ive tried. Can anyone help me with this? Thanks

Ryan

Have you tried the plain DateTime data type?|||

Hi Ryan,

The timestamp in SQL Server maps to a Byte[] type in .NET framework. It is not used as DateTime. It is a data type that exposes automatically generated, unique binary numbers within a database. timestamp is generally used as a mechanism for version-stamping table rows.

If you just need to store date/time information, try to use datetime data type, it maps to a DateTime object in .NET framework.

Please check the following link for more information:

http://msdn2.microsoft.com/en-us/library/ms182776.aspx
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconmappingnetdataproviderdatatypestonetframeworkdatatypes.asp

HTH. If this does not answer your question, please feel free to mark the post as Not Answered and reply. Thank you!

Sunday, February 12, 2012

Business Intelligence Report Parameter Prompt Multi

I have my 2 datasets and my parameter set up to display building to select from. My issue is I get multiple values in the Select Value Prompt. It will pull the correct data I just want to clean up the Select Value Prompt.

Example:

Building 1

Building 1

Building 1

Building 2

Building 2

Dataset 1:

Select *

From Table

Dataset 2:

SELECT *

From Table

WHERE (Table.Building = @.Building)

ORDER BY Client.ctg

I'm assuming that you're using Dataset1 to populate the parameter. If so, try using the keyword DISTINCT in your SQL query for Dataset1.

SELECT DISTINCT
BuildingNameField
FROM Table (NoLock)
ORDER BY BuildingNameField

|||I can't use the distinct because it will cut down my data and not give me an accurate query. Unless the is a way to do it that I am not aware of. What is the (nolock)?|||What had to do is make a 3rd dataset in the report, w/ just the select distinct statement in it and then, change the available values dataset to the one that is just the select distinct.|||

The "nolock" (also written as "with nolock") insures that the table isn't locked while running the query. I always use this as a general practice when I'm running a query that really doesn't need to lock the table.

About 99.9% of the time, I always create a seperate dataset for parameters. This way, if you need to make changes to the dataset, you don't have to worry about screwing up data for something else.

Thanks,

Micheal