C SQLite Insert mit Variable

DonConto

Commander
Registriert
Juli 2004
Beiträge
2.220
Vorab: Ich habe keine Ahnung von C. Trotzdem versuche ich anhand von Beispielen und Tutorials ein kleines Programm für mein trautes Heim zu basteln. Folgendes Problem habe ich jedoch:

Der SQLite Insert
Code:
"INSERT INTO SMAEM (L1imp) VALUES (33)";
funktioniert wunderbar. Aber mir ist es nicht gelungen, statt einem statischen Wert (hier die 33) eine Variable (hier L1i) in die SQLite DB zu schreiben. Aber egal was ich versuche, ich habe entweder ein NULL in der DB oder bekomme einen SQL Fehler.

Mag sich jemand herab lassen und mir hier einen Tipp geben oder ggf. sogar das Programm so anpassen, dass es funktioniert?

Premium wäre, wenn das auch mit mehreren Variablen funktioniert:
Code:
"INSERT INTO SMAEM (L1imp,L1exp) VALUES (33,129)";

Danke!

Code:
sqlite3 *db;
   char *zErrMsg = 0;
   int rc;
   char *sql;

   /* Open database */
   rc = sqlite3_open("/var/www/lite/db1", &db);
   if( rc ){
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      exit(0);
   }else{
      fprintf(stderr, "Opened database successfully\n");
   }
   printf ("L1i: %i\n",L1i/10);
   /* Create SQL statement */
   sql = "INSERT INTO SMAEM (L1imp) VALUES (33)";
  
   /* Execute SQL statement */
   rc = sqlite3_exec(db, sql, callback, 0, &zErrMsg);
   if( rc != SQLITE_OK ){
      fprintf(stderr, "SQL error: %s\n", zErrMsg);
      sqlite3_free(zErrMsg);
   }else{
      fprintf(stdout, "Records created successfully\n");
   }
   sqlite3_close(db);
   return 0;
 
Es gäbe zwar einen recht kurzen (aber sicherheitstechnisch kritischen) Weg das zu realisieren... besser wäre es aber wenn du dir die Prepared Statements von SQLite anschauen würdet. Da arbeitest du mit Platzhaltern im Statement und bindest die werte per zusätzlicher API-Aufrufe mit an das Statement.

https://www.sqlite.org/c3ref/prepare.html
 
Hi Jesterfox!
Mir ist bewusst, dass das eine Quick and Dirty Lösung ist. Ich weise nochmals auf den ersten Satz meines Postings hin :-) Da das Programm ausschliesslich auf dem Raspberry in meinem Heimnetz läuft, sollte das sicherheitstechnisch kein allzu großes Risiko sein (unter Berücksichtigung von Eintrittswahrscheinlichkeit und Schadensausmaß).

Deinen Link habe ich mir angeschaut. Aber das sind für mich nur böhmische Dörfer ohne ein paar Beispiele :-(
 
Quick & Dirty wäre sprintf(). Funktioniert ähnlich wie fprintf nur das er einen neuen String erzeugt.

Ganz grob (hab schon länger kein C mehr programmiert)

Code:
/* Create SQL statement */
sprintf(sql, "INSERT INTO SMAEM (L1imp) VALUES (%i)", L1i);

Zu den möglichen Problemen SQL Strings einfach so zusammenzusetzen einfach mal zum Thema "SQL Injection" einlesen. Damit kann man sich nämlich gehörige Sicherheitlücken bauen ;-)
(bei reinen Zahlenwerten ist das noch recht unkritisch, Strings als Werte sind schlimmer da sie beliebigen Code enthalten könnten)


Edit: args, seh grad das meine C Kenntnisse schon zu stark eingerostet sind, da ist noch ein Fehler drin.... für sprintf muss der String vorher allokiert werden... doofe Sache wenn man nicht weiß wie lang das Statement wird.

Edit2: würde bedeuten das du "sql" so deklarieren musst:

char sql[100];

Wobei du sicherstellen musst das der SQL-String nie länger wird als die Angegebenen Zeichen Minus 1, da du ansonsten dir den Speicher zerschreibst. Das ist wirklich "dirty" ohne das man noch zusätzlichen Aufwand treibt... evtl. meldet sich ja noch jemand mit besseren Ideen.
 
Zuletzt bearbeitet:
Vor deinem Edit2 hatte ich das mal mit char sql[1000]; probiert. Da ich max. 6 Werte schreiben muss und jeder Wert nur max. 4-stellig sein kann, kann man das sicherlich noch sinnvoll kürzen. Aber ich denke den Aufwand kann ich mir für das Projekt sparen. Mir ist durchaus klar, dass das alles sehr dirty ist :-)
 
Prepared Statements wären trotzdem die bessere Lösung, weil man da das Problem mit dem möglichen Speicherüberlauf nicht hat und der Aufwand nun wirklich nicht hoch ist:

Ungetestet:
Code:
sqlite3_stmt* stmt = NULL;
sqlite3_prepare_v2(db, "INSERT INTO tabelle (feld1, feld2) VALUES (?,?)", -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, wert1);  // Ja, der Index startet wirklich bei 1
sqlite3_bind_int(stmt, 2, wert2);
sqlite3_step(stmt);      // stmt ausführen
sqlite3_finalize(stmt);  // stmt zerstören

Interessant sind ja vor allem die bind-Funktionen, von denen für eigentlich jeden wichtigen Typen eine existiert.
 
Zurück
Oben