LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Initializing an array of clusters in a CIN?

I'm trying to write a CIN to connect to a mySQL database, retreive some information, and return it to labVIEW for display. The connection works perfectly using ODBC, but I'm having major trouble getting the information back to LabVIEW. I'm new to CINs and I'm still slightly confused as to how the different structures work. I want to return the data in an array of clusters (using struct names, a 'Set' of 'Records'). LV generated the structs, and I simply renamed some of the fields/names. The code I have so far works up to the point specified in the source below, when I try to initialize the array for data entry. I think what's throwing me off is the conplexity of my structures. Since it's an array of clusters, and not an array of say strings or integers, I'm getting confused. If anyone could help me out by telling me what's wrong with my code, and/or filling in the section of the while loop I'm rather clueless on.


typedef struct {
LStrHandle Number;
LStrHandle SerialNumber;
} Record;

typedef struct {
int32 dimSize;
Record ptr[1];
} Set;
typedef Set **SetHdl;

MgErr CINRun(COpt *ConnectionOptions, LStrHandle *Number, SetHdl *RecordSet);

MgErr CINRun(COpt *ConnectionOptions, LStrHandle *Number, SetHdl *RecordSet)
{
// LV error code
MgErr err = noErr;

// ODBC environment variables
HENV env = NULL;
HDBC dbc = NULL;
HSTMT stmt = NULL;

// Connection options data variables
UCHAR* dsn = malloc(SQL_MAX_DSN_LENGTH * sizeof(UCHAR));
UCHAR* user = malloc(32 * sizeof(UCHAR));
UCHAR* pass = malloc(32 * sizeof(UCHAR));
UCHAR* num = malloc(16 * sizeof(UCHAR));

// Query variables
INT qlen;
INT nlen;

UCHAR colNumber[5];
SDWORD colNumberSize;
UCHAR* query;
INT numRows;

// ODBC return code storage
RETCODE retcode;

/** Prepare data from LV for C++ manipulation **/
strcpy(dsn, LStrBuf((LStrPtr)(*(ConnectionOptions->DSN))));
dsn[(*(ConnectionOptions->DSN))->cnt] = '\0';

strcpy(user, LStrBuf((LStrPtr)(*(ConnectionOptions->Username))));
user[(*(ConnectionOptions->Username))->cnt] = '\0';

strcpy(pass, LStrBuf((LStrPtr)(*(ConnectionOptions->Password))));
pass[(*(ConnectionOptions->Password))->cnt] = '\0';

strcpy(num, LStrBuf((LStrPtr)(*Number)));
// Program crashes here too, but that's the least of my concerns right now. Keep reading down.
//num[(**Number)->cnt] = '\0';

qlen = (int)strlen(
"SELECT m.Number FROM master AS m WHERE (m.Number LIKE '');"
);
nlen = (int)strlen(num);

query = malloc((qlen + nlen + 1) * sizeof(UCHAR));
sprintf(query,
"SELECT m.Number FROM master AS m WHERE (m.Number LIKE '%s'\0);",
num);

// Prepare and make connection to database
SQLAllocEnv (&env);
SQLAllocConnect(env, &dbc);

retcode = SQLConnect(dbc, dsn, SQL_NTS, user, SQL_NTS, pass, SQL_NTS);

// Test success of connection
if (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{
retcode = SQLAllocStmt(dbc, stmt);
retcode = SQLPrepare(stmt, query, sizeof(query));
retcode = SQLExecute(stmt);

SQLBindCol(stmt, 1, SQL_C_CHAR, colNumber, sizeof(colNumber), &colNumberSize);
SQLRowCount(stmt, &numRows);

//Program crashes on the following line. I get an error in LV saying something about an error in memory.cpp

DSSetHandleSize((*RecordSet), sizeof(int32) + (numRows * sizeof(Record)));
(**RecordSet)->dimSize = numRows;

retcode = SQLFetch(stmt);
numRows = 0;

while (retcode == SQL_SUCCESS || retcode == SQL_SUCCESS_WITH_INFO)
{

/* Need code here to retreive/create Records and put them in the array */

retcode = SQLFetch(stmt);
numRows++;
}

SQLDisconnect(dbc);
}
else
{

}

// Free ODBC environment variables

SQLFreeConnect(dbc);
SQLFreeEnv(env);

// Return LV error code
return err;
}
0 Kudos
Message 1 of 9
(4,014 Views)
This looks incorrect:
MgErr CINRun(COpt *ConnectionOptions, LStrHandle *Number, SetHdl *RecordSet)

Did you let LabVIEW generate the C file??

When you pass an array of clusters to a CIN, what is passed is a handle to the array. You are declaring a pointer to a handle. I just did a test passing an array of clusters to a CIN. The C file looks like this (comments are mine):


typedef struct {
int32 Num1;
int32 Num2;
} TD2; // the cluster


typeDef struct {
int32 dimSize;
TD2 Cluster[1];
} TD1; // the array

typeDef TD1 **TD1Hdl; // handle to the array

CIN MgErr CINRun(TD1Hdl Array);



Notice that it passes you a HANDLE, not a pointer to a handle.

On this line:

DSSetHandleSize((*RecordSet), sizeof(int32) + (numRows * sizeof(Record)));

If RecordSet is a HANDLE, then (*RecordSet) is a POINTER - you are passing a POINTER to a routine that expects a HANDLE.

The line:
(**RecordSet)->dimSize = numRows;
Is also incorrect - if RecordSet is a HANDLE, then (*RecordSet) is a POINTER, and (**RecordSet) is an ARRAY, but you're asking it to be a pointer. (*RecordSet)->dimSize would be the size to fetch.

Read the rules again on what is passed to CINs.

I strongly suggest developing the interface first - the VI that calls the CIN. Put the CIN in place and let LabVIEW generate the initial C file.
Then modify the code to do something simple with the input arguments, like fetch the array size, and put this number into an output argument. Something VERY basic, just to test the ins and outs. Debug this until all ins and outs are working.

THEN AND ONLY THEN add code to do whatever work needs doing.
Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


LinkedIn

Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 2 of 9
(4,014 Views)
LabVIEW 7.0 did generate that function prototype, and every other one I've been using. All of the parameters it's ever defined have been pointers. I will try changing it.
0 Kudos
Message 3 of 9
(4,014 Views)
I forgot to say that I HAVE completed the LV interface. I just posted another question regarding a very very simple CIN, and I will now go test what you're saying. Why do you think LV created the function header with pointers?
0 Kudos
Message 4 of 9
(4,014 Views)
I tested it again, and LV 7.0 DEFINATELY generates function headers with pointer parameters. However, on a different computer in my office, we have 6.1i installed, and we tested it there, and it did not generate a header with pointers. This leads me to believe that this is a bug with 7.0, and it should be addressed immediately.

Please note that if LV had been passing pointers, my code would have been correct. However, I really thank you for you help.
0 Kudos
Message 5 of 9
(4,014 Views)
I neglected to mention that my test was done with LV 6.1.

I just tested again in 7.0 and indeed, the argument is a POINTER to a handle - they've changed it. I've used CINs since LabVIEW 2.0 (1989) and arrays have always been passed by Handle.

So some of my comments are incorrect for LV 7.

I would make sure about the other calls (SetHandleSize) - have they been changed as well?

I would also stick with the plan of going slowly - making sure the ins and outs work, then making sure the SetHandleSize calls work, and THEN put the meat onto the bones.
Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


LinkedIn

Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 6 of 9
(4,014 Views)
Well you're right and you're wrong. Almost all of my errors go away when I change the function header, and the rest of my program works as planned. So I reiterate: Thank you and I think this is a bug in LV 7. I've mailed NI.
0 Kudos
Message 7 of 9
(4,014 Views)
Well, It's good to know that. Make sure you report it - that's a biggie!

I think the LStrHandle is the same way - LV passes a HANDLE, not a pointer.
Steve Bird
Culverson Software - Elegant software that is a pleasure to use.
Culverson.com


LinkedIn

Blog for (mostly LabVIEW) programmers: Tips And Tricks

0 Kudos
Message 8 of 9
(4,014 Views)
I did report it. I connected all the data types to a CIN and tested which are passed by pointer, and in 6.x if it's a Handle, it's not passed by pointer, but otherwise it is. This convention seems to work in 7, even though LV creates the header with everything passed by pointer.
0 Kudos
Message 9 of 9
(4,014 Views)