TDBXValue only provides String values

I have a simple Datasnap Server application and  Client Application.
The server has a method  ATable(int) that returns a TDBXReader* representing the result of a query.
The dataset  has column types of char (40) and integer and Boolean.
My client code is able to extract the char(40) columns from the dataset using the TDBXValue->GetAnsiString() method but any other column type always returns a value of zero when calling the appropriate type such as TDBXValue->AsInt32 for an integer column;

Is this normal ?
I have provided a sort of fix by changing the query text to convert integer column values to strings with the SQL STR function etc.
This however requires more effort on the client side in re-coding the integer columns back to integers. Is there a way to fix this ?

The relevant Server and client code is attachedDatasnapServerAndclient.txt
LVL 2
Roger AlcindorAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Sinisa VukSoftware architectCommented:
you forget to add this line before case where you want to get integer:
value = reader->Value[i];

Open in new window


...so it can be:
                                        valuetype = reader->ValueType[i];
					t = valuetype->DataType;
                                        value = reader->Value[i];
					if(t==ftString)
					{
						if((s=value->GetAnsiString()).IsEmpty())
							s = "NULL";
					}
					else
					switch(t)
					{
						case ftInteger:
							 w   =  value->AsInt32;
						break;
						case ftFloat:
							 dbl = value->AsDouble;
						break;
						case ftBoolean:
							 s = value->AsInt8;
						break;
						default:
						break;
					}

Open in new window

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
sarabandeCommented:
to add to above solution:

you defined all variables used at begin of your function without initialization. this actually is bad coding as you loose the overview which variable was needed to be set in a context and which one already has a proper contents.

so if you would remove the definitions for valuetype, t, and value from the top and put it at the place where you need the variables like


for(int i=0;i<numcols;i++)
{    
     try
    {
        TDBXValueType  * valuetype = reader->ValueType[i];
	TFieldType t = valuetype->DataType;
        TDBXValue  * value = reader->Value[i];
        ....

Open in new window


you see, with the above, the compiler would have complained that 'value' was not defined in the else branch.

Sara
Roger AlcindorAuthor Commented:
Many thanks for that, I have another problem now in that when testing for a null value with the value->IsNUL() method, an access violation exception is thrown rather than returning true/false (but not always).
IT Pros Agree: AI and Machine Learning Key

We’d all like to think our company’s data is well protected, but when you ask IT professionals they admit the data probably is not as safe as it could be.

sarabandeCommented:
testing for a null value with the value->IsNUL()
i would suggest to test for a null by

if (value == NULL || value->IsNUL())
{
         ...

Open in new window


if the condition (value == NULL) is true, the second condition value->IsNul() was not executed what prevents from access violation.

Sara
Roger AlcindorAuthor Commented:
I performed the value==NULL check first and it always failed (was not NULL).
I will persevere a bit longer and maybe raise a new question.
Thanks for the comment anyway.
sarabandeCommented:
access violation exception is thrown
access violation means pointer error. if the pointer 'value' is not NULL you should check whether it was initialized to NULL wherever it was defined and that it wasn't defined twice.

for example if you have

void some_function()
{
      TDBXValue  * value;   // not initialized. it may have any contents and might crash if used
      ....
      for (...)
      {
            ...
            if (....)
            {
                 TDBXValue  * value = reader->Value[i]; ; // this is a new pointer variable. 
                                                              // which is only valid in the current if block 
                                                              // note, the pointer 'value' defined at top will not change
                ...         
            }
            else 
            {
                    int ival = value->AsInt32;  // Kaboom. it uses uninitialized pointer from top

Open in new window


note, the above would not always crash since the arbitrary contents of the pointer also can be a valid address in memory (what could allow access without crash in some cases).

there are some rules to avoid most pointer errors:

- you should not define a second variable with same name of another variable which still is in an open scope.

- you should initialize any variable.

- you should check each pointer that you received from a function or as argument for null value.

- you should 'delete' each pointer that you created with 'new'. after delete assign NULL to the variable (even if it is last statement or destructor).
- you should 'free' each pointer that you got by a call to malloc, calloc, or realloc and set it NULL after.

- avoid allocating memory for a pointer in a function and free it in another function or by the caller. that is bad code (beside of a create function which replaces the 'new').

Sara
Roger AlcindorAuthor Commented:
The issue with value->IsNull() is now solved. I compiled the same client code on Embarcadero EX8 and it runs without error and correctly returns true when a column in the dataset is NULL.
Previously I was using Embarcadero XE3.
sarabandeCommented:
even if it runs now with your old code, you may nevertheless add the recommended safety checks and initializations. those wouldn't harm and help from crashes if for example you change to a new empty database table or when access to the server was down.

Sara
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Delphi

From novice to tech pro — start learning today.