Store QList<QVariant> to PostgreSQL database in Qt - qt

My question is similar to this one: link except that I don't want to serialize the QList. I want to store a QList as a double precision array in the DB table.
I am trying the following bindValue command for the variable val:
query.bindValue( QStrFromSrcEnc( id ), QVariant::fromValue( val ) );
where val is QList and id is ":value"
I am executing the following postgres query:
"INSERT INTO valtable( type_id, asset_id, value, tag )\n"
"VALUES ( :typeId, :assetId, :value, :tag )\n"
The value column of the table is of the type double precision[].
I get the following error, as you can see the 3rd field for value is blank which means val wasn't bound correctly.
ERROR: syntax error at or near ","
LINE 1: EXECUTE qpsqlpstmt_13e (60, 63, , '')
^
however, if val is simply a QVariant, then it works fine.

Ok, I did a workaround.
I convert the QList List to a QString in a postgres array format (e.g.'{1.32,4.43}').
QString valueStr = QStrFromSrcEnc("{");
for(int i=0; i<List.size(); ++i)
{
valueStr += QString::number( List[i] );
valueStr += QStrFromSrcEnc(",");
}
valueStr.chop(1);
valueStr += QStrFromSrcEnc("}");
then I bind the string value to the :val placeholder

Related

Go/golang sqlite query not returning any rows

I am new to go and trying to retrieve data from a sqlite database.
Im using github.com/mattn/go-sqlite3 as sqlite driver.
The query I m sending does not return any results even though it should. I tried the query my programme is generating manually and it returns data as it should when I use the query manually as well as when I send it via my programme.
Here is my code:
for index := range Array {
id, _ := strconv.Atoi(Array[index])
rand.Seed(time.Now().UnixNano())
RandomNr := rand.Intn(100)
fmt.Printf("index: %d - randomnr: %d \n", id, RandomNr)
rows, errROW := db.Query("SELECT user.id,user.name,stage.link,player.url,player.characterchance,player.chance FROM user,stage,player WHERE user.id = '%d' AND '%d' <= user.chance AND stage.user = user.id AND stage.domain = player.id AND player.chance > 0 ORDER BY player.id ASC \n",id, RandomNr)//.Scan(&idr, &name, &link, &url, &characterchance, &chance)
//this is what the finished query looks like and it returns the rows as its supposed to
//rows, errROW := db.Query("SELECT user.id,user.name,stage.link,player.url,player.characterchance,player.chance FROM user,stage,player WHERE user.id = '203' AND '33' <= user.chance AND stage.user = user.id AND stage.domain = player.id AND player.chance > 0 ORDER BY player.id ASC")
if errROW != nil {
fmt.Println("errROW")
log.Println(errROW)
}
defer rows.Close()
if rows.Next() == false {
fmt.Println("no rows ")
}
for rows.Next() {
fmt.Println("where are the rows")
var id int
var name string
var link string
var url string
var characterchance int
var chance int
rows.Scan(&id, &name, &link, &url, &characterchance, &chance)
fmt.Println(id,name,link,url,characterchance,chance)
}
rows.Close()
}
}
This query can return multiple and single rows. I also tried retrieving the data via QueryRow as a single row which also did not return any result.
Any help would be much appreciated.
UPDATE:
I added
if rows.Next() == false
as an attempt to find the problem. Removing it yields the same result. Furthermore I do not get an error message from scan. The for rows.next() loop does not even get executed.
when you do:
if rows.Next() == false
you are scrolling to the first row
and
for rows.Next()
moves to the next row
basically, you are skipping the first row in your result set in the example code you provided.
also, you are ignoring the error in Scan.
This looks like it would print something if the query returns at least 2 rows (since first row is being skipped)
Ok I figured out what the problem was:
In my query I used: %d as a placeholder for my variable when I should have used $1,$2 etc. Using this the query returns results as expected.
It seems strange to me that this behaviour is allowed returns no error from go or sqlite and even works when you just printout the query and use it with sqlite3 manually. Coming from C and just starting out with go this can obviously be the cause for some headaches.

Wrong "Spacing" and "Origin" of a DICOM series in ITK

When I read a dicom series with a series reader in itk,
I always find the origin=[0 0 0] and spacing=[1 1 1], the same for all different datasets.
* main function:-
void main()
{
reader = READ_DCM(Input_DCM_Paths[0]);
cout<<" Reading Done!!"<<endl;
cout<< " Origin: " <<reader->GetOutput()->GetOrigin()<< endl;
cout<< " Spacing: " <<reader->GetOutput()->GetSpacing()<< endl;
}
* reader function:-
SeriesReaderType::Pointer READ_DCM (std::string InputFolder)
{
SeriesReaderType::Pointer seriesReader = SeriesReaderType::New();
seriesReader->SetImageIO(itk::GDCMImageIO::New());
itk::GDCMSeriesFileNames::Pointer nameGenerator = itk::GDCMSeriesFileNames::New();
nameGenerator->SetUseSeriesDetails(true);
nameGenerator->SetDirectory(InputFolder);
std::string seriesID = nameGenerator->GetSeriesUIDs().begin()->c_str();
seriesReader->SetFileNames(nameGenerator->GetFileNames(seriesID));
seriesReader->Update();
return seriesReader;
}
* 1st series output in itk:-
* 1st series output in matlab:-
What's worng with my 'series reader' code ??
I followed the "reading part" in this example.
I have the same problem, i use following similar codes to read dicom series, but the output of spacing between slices is sometimes correct BUT not always:
// 1) Read the input series
typedef itk::GDCMImageIO ImageIOType;
typedef itk::GDCMSeriesFileNames InputNamesGeneratorType;
ImageIOType::Pointer gdcmIO = ImageIOType::New();
InputNamesGeneratorType::Pointer inputNames=InputNamesGeneratorType::New();
inputNames->SetInputDirectory( dirPath );
inputNames->AddSeriesRestriction("0020|0013");
// then i select a serie identifier and pass it to the reader
typedef itk::ImageSeriesReader< CTImageType > ReaderType;
ReaderType::Pointer reader = ReaderType::New(); ;
reader->SetImageIO( gdcmIO );
reader->SetFileNames( inputNames->GetFileNames( seriesIdentifier.c_str() ));
reader->UpdateOutputInformation();
--->>> reader->GetOutput()->GetSpacing()[2] is not correct always!!!
ITK/SimpleITK assume that when you provide a series of images the files are in the same order as the slices. For many collections this is not the case and you have to presort the files (more details for python here) based on the Slice Location tag (or .GetOrigin).

Retrieving row count from QSqlQuery, but got -1

I'm trying to get the row count of a QSqlQuery, the database driver is qsqlite
bool Database::runSQL(QSqlQueryModel *model, const QString & q)
{
Q_ASSERT (model);
model->setQuery(QSqlQuery(q, my_db));
rowCount = model->query().size();
return my_db.lastError().isValid();
}
The query here is a select query, but I still get -1;
If I use model->rowCount() I get only ones that got displayed, e.g 256, but select count(*) returns 120k results.
What's wrong about it?
This row count code extract works for SQLite3 based tables as well as handles the "fetchMore" issue associated with certain SQLite versions.
QSqlQuery query( m_database );
query.prepare( QString( "SELECT * FROM MyDatabaseTable WHERE SampleNumber = ?;"));
query.addBindValue( _sample_number );
bool table_ok = query.exec();
if ( !table_ok )
{
DATABASETHREAD_REPORT_ERROR( "Error from MyDataBaseTable", query.lastError() );
}
else
{
// only way to get a row count, size function does not work for SQLite3
query.last();
int row_count = query.at() + 1;
qDebug() << "getNoteCounts = " << row_count;
}
The documentation says:
Returns ... -1 if the size cannot be determined or if the database does not support reporting information about query sizes.
SQLite indeed does not support this.
Please note that caching 120k records is not very efficient (nobody will look at all those); you should somehow filter them to get the result down to a manageable size.

How do you compare versions in InstallScript?

It looks like there is a builtin function, VerCompare, but it requires strings that have all four components, e.g. 1.2.3.4. I haven't tried to do string manipulation in InstallScript and was hoping someone already had the code to take a version string and add .0's as necessary.
Needs some error checking, but here's the general idea:
prototype NUMBER CompareVersions(STRING, STRING);
prototype STRING FormatVersion(STRING);
function NUMBER CompareVersions(leftVersion, rightVersion)
STRING formattedLeftVersion, formattedRightVersion;
begin
formattedLeftVersion = FormatVersion(leftVersion);
formattedRightVersion = FormatVersion(rightVersion);
return VerCompare(formattedLeftVersion, formattedRightVersion, VERSION);
end;
function STRING FormatVersion(version)
STRING formattedVersion;
LIST tokens;
NUMBER count;
begin
tokens = ListCreate(STRINGLIST);
StrGetTokens(tokens, version, ".");
count = ListCount(tokens);
ListSetIndex(tokens, LISTLAST);
while (count < 4)
ListAddString(tokens, "0", AFTER);
count = count + 1;
endwhile;
StrPutTokens(tokens, formattedVersion, ".", FALSE);
ListDestroy(tokens);
return formattedVersion;
end;

EXC_BAD_ACCESS on inserting

I'm using FMDatabase to operate on an sqlite3 database. Here's my code:
NSString *dbFilePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#"temp_info.db"]];
FMDatabase *fmdb = [FMDatabase databaseWithPath:dbFilePath];
if (![fmdb open]) {
NSLog(#"......");
} else {
NSString *sql = #"CREATE TABLE IF NOT EXISTS test1(id INTEGER, name TEXT, create_time TEXT)";
if (![fmdb executeUpdate:sql]) {
NSLog(#"......");
}
for (int i = 0; i < 3; i++) {
BOOL result = [fmdb executeUpdate:#"INSERT INTO test1(id, name, create_time) values(?,?,?)", i+1, #"test", #"12-09-10 12:10"];
NSLog(#"%d", result);
}
// EXC_BAD_ACCESS
}
When I run the line:
BOOL result = [fmdb executeUpdate:#"INSERT INTO test1(id, name, create_time) values(?,?,?)", i+1, #"test", #"12-09-10 12:10"];
I get an EXC_BAD_ACCESS error. Why?
question has been solved!
*1.*All arguments provided to the -executeUpdate: method(or any of the variants that accept a va_list as a parameter) must be objects.The following will be not work (and will result in a crash):
[db executeUpdate:#"INSERT INTO mytable VALUES (?)", 66];
The proper way to insert a number is to box it in an NSNumber object:
[db executeUpdate:#"INSERT INTO mytable VALUES (?)", [NSNumber numberWithInt:66]];
*2.*Alternatively,you can use the -execute*WithFormat: variant to use NSString-style substitution:
[db executeUpdateWithFormat:#"INSERT INTO mytable VALUES (%d)", 66];
Internally,the -execute*WithFormat: methods are properly boxing things for you.The following percent modifiers are recognized:%#,%c,%s,%d,%D,%i,%u,%U,%hi,%hu,%qi,%qu,%f,%ld,%lu,%lld,and %llu.Using a modifier other than those will have unpredictable results.If,for some reason,you need the % character to appear in your SQL statement,you should use %%.

Resources