Frage zu ODBC (Labview)

Frage zu ODBC (Labview)

am 20.11.2006 10:46:29 von Jan Schmidt

Hallo NG,

gegeben sei folgende Tabelle

CREATE TABLE `idtest` (
`id` int(10) unsigned NOT NULL auto_increment,
`zeit` timestamp(14) NOT NULL,
PRIMARY KEY (`id`)
) TYPE=MyISAM;

Die id bei jedem Einfügen erhält man normalerweise über

INSERT INTO idtest (zeit) VALUES(now());select @@identity

Nun funktioniert das ganze mittels Labview nicht, die Fehlermeldung
suggeriert, daß der ODBC-Treiber nur ein SQL-Statement pro Abfrage
zuläßt.

Wie kann man das anders lösen?

Gruß,
Jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 11:33:47 von Andreas Kretschmer

Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de

Re: Frage zu ODBC (Labview)

am 20.11.2006 12:05:55 von Jan Schmidt

Andreas Kretschmer writes:

> begin Jan Schmidt schrieb:
>> Die id bei jedem Einfügen erhält man normalerweise über
>>
>> INSERT INTO idtest (zeit) VALUES(now());select @@identity
>>
>> Nun funktioniert das ganze mittels Labview nicht, die Fehlermeldung
>> suggeriert, daß der ODBC-Treiber nur ein SQL-Statement pro Abfrage
>> zuläßt.
>>
>> Wie kann man das anders lösen?
>
> Wenn das wirklich die Ursache ist, dann hole doch die ID in einer 2.
> Abfrage. Sie sollte sich ja nicht ändern für diese Session.

Naja, das war ein Trivialbeispiel. Normalerweise wird ein Eintrag
angelegt, der später mit Update bearbeitet wird. Mehrere Datenquellen
erzeugen gleichzeitig (auch vom selben Client / Programm) die Einträge.

Ich brauche also eine eindeutige ID, die entweder von der DB
bereitgestellt wird, oder die ich erzeuge (Problem: wie) und mit der
ich dann den jeweils gültigen Eintrag auswählen kann. Die Zeit eignet
sich dazu nur bedingt, weil die Auflösung mit 1s zu grob ist. Außerdem
will ich nicht unbedingt noch ein Feld, was ich eigentlich nicht
brauche mitschleppen.

Alternative wäre m.E. nur eine Semaphore in der Datenbank z.B. mittels
stored procedure, was aber aufgrund von Version 4.0.21 nicht geht.

Gruß,
jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 12:24:28 von Andreas Kretschmer

Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de

Re: Frage zu ODBC (Labview)

am 20.11.2006 12:41:40 von Jan Schmidt

Andreas Kretschmer writes:

> begin Jan Schmidt schrieb:
>>>> INSERT INTO idtest (zeit) VALUES(now());select @@identity
>>>>
>>>> Nun funktioniert das ganze mittels Labview nicht, die Fehlermeldung
>>>> suggeriert, daß der ODBC-Treiber nur ein SQL-Statement pro Abfrage
>>>> zuläßt.
>>>>
>>>> Wie kann man das anders lösen?
>>>
>>> Wenn das wirklich die Ursache ist, dann hole doch die ID in einer 2.
>>> Abfrage. Sie sollte sich ja nicht ändern für diese Session.
>>
>> Naja, das war ein Trivialbeispiel. Normalerweise wird ein Eintrag
>> angelegt, der später mit Update bearbeitet wird. Mehrere Datenquellen
>> erzeugen gleichzeitig (auch vom selben Client / Programm) die Einträge.
>>
>> Ich brauche also eine eindeutige ID, die entweder von der DB
>> bereitgestellt wird, oder die ich erzeuge (Problem: wie) und mit der
>
> Der normale Weg dafür sind Sequencen. In MySQL nennt sich das wohl
> AutoIncrement.

ja, das wollte ich auch.

>> ich dann den jeweils gültigen Eintrag auswählen kann. Die Zeit eignet
>> sich dazu nur bedingt, weil die Auflösung mit 1s zu grob ist. Außerdem
>> will ich nicht unbedingt noch ein Feld, was ich eigentlich nicht
>> brauche mitschleppen.
>
> Dieses Feld wäre dann der PK für die table. Und die Vergabe einer
> solchen unique ID ist Aufgabe des DB-Systems, und auch die
> Sicherstellung der Eindeutigkeit etc. Ich nix MySQL, in PostgreSQL
> arbeitet man da mit currval(), da gibt es sicher was vergleichbares in
> MySQL.

da habe ich nur das gefunden:

http://dev.mysql.com/doc/refman/5.1/de/mysql-insert-id.html

Aber dafür muß ich zwei Anweisungen am Stück übertragen, was mir nicht
gelingen will.

Ich brauche also bildich gesprochen eine Möglichkeit, daß insert
direkt die ID zurückliefert, ohne daß ich ein Semikolon in der
Anweisung habe.

jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 12:50:14 von Andreas Kretschmer

Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de

Re: Frage zu ODBC (Labview)

am 20.11.2006 13:23:26 von Jan Schmidt

Andreas Kretschmer writes:

> begin Jan Schmidt schrieb:
>>> Dieses Feld wäre dann der PK für die table. Und die Vergabe einer
>>> solchen unique ID ist Aufgabe des DB-Systems, und auch die
>>> Sicherstellung der Eindeutigkeit etc. Ich nix MySQL, in PostgreSQL
>>> arbeitet man da mit currval(), da gibt es sicher was vergleichbares in
>>> MySQL.
>>
>> da habe ich nur das gefunden:
>>
>> http://dev.mysql.com/doc/refman/5.1/de/mysql-insert-id.html
>
> ich denke, Du verwendest 4.0.x?

ja, aber da ist _das_ auch nicht anders. Allerdings könnte ich bei 5.x
eine stored procedure generieren, die mir insert und select kombiniert
und die ID zurückliefert und somit das DB-Problem mit DB-Mitteln
lösen.

>> Aber dafür muß ich zwei Anweisungen am Stück übertragen, was mir nicht
>> gelingen will.
>
> Warum?

weil ich nicht sicherstellen kann, daß nicht ein anderer Thread
zwischen insert und select selbst ein insert absetzt (s.u.).

> ---Zitat
> Der Wert von mysql_insert_id() wird nur von Anweisungen beeinflusst, die
> innerhalb der aktuellen Clientverbindung gegeben werden, aber nicht
> durch Anweisungen von anderen Clients.
> ---Zitat
>
> Das steht auf der Dir genannten Seite. Wie es es, das mal selbst zu
> lesen?

hab ich auch gemacht - allerdings nützt mir das nur bedingt was, weil
ich von dem selben Programm aus mehrere Inserts gleichzeitig machen
muß bzw. das nicht sicher ausschließen kann und ich mir den Aufwand
eine Semaphore zu implementieren sparen wollte.

Gruß,
jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 13:35:43 von Andreas Kretschmer

Andreas
--
Andreas Kretschmer
Linux - weil ich es mir wert bin!
GnuPG-ID 0x3FFF606C http://wwwkeys.de.pgp.net
Deutsche PostgreSQL User Group: http://pgug.de

Re: Frage zu ODBC (Labview)

am 20.11.2006 14:15:06 von Jan Schmidt

Andreas Kretschmer writes:

>> hab ich auch gemacht - allerdings nützt mir das nur bedingt was, weil
>> ich von dem selben Programm aus mehrere Inserts gleichzeitig machen
>> muß bzw. das nicht sicher ausschließen kann und ich mir den Aufwand
>> eine Semaphore zu implementieren sparen wollte.
>
> Ich glaube, da ist ein Fehler in der Überlegung. Wenn es ein Problem
> wäre, daß zwischen dem INSERT und der Abfrage der ID ein weiteres INSERT
> erfolgen kann, so ist es egal, ob Du der DB diese zwei Anweisungen auf
> einen Schlag oder in 2 Schritten gibst, denn auch im ersteren Fall
> könnte ja ein INSERT dazwischen erfolgen.

Hmm, ich war jetzt davon ausgegangen, daß der Server das quasi atomar
bearbeitet, was ihm im selben Buffer übergeben wird, also so eine Art
Fifo-Bearbeitung. Wenn der Server die Anweisungen umsortieren kann,
geht das dann natürlich nicht (habe ich nicht getestet).

> So, nun bin ich mir nicht ganz sicher, aber ich vermute einfach mal,
> daß, wenn Dein Programm mehrere Threads macht, jeder seine eigene
> Session auf der DB hat. Damit ist Dein Problem nicht existent.

das ist ein guter Tip - das probiere ich mal aus.

Gruß,
jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 14:55:51 von Axel Schwenke

Jan Schmidt wrote:
> Andreas Kretschmer writes:
>
>> begin Jan Schmidt schrieb:
>>> Die id bei jedem Einfügen erhält man normalerweise über
>>>
>>> INSERT INTO idtest (zeit) VALUES(now());select @@identity

Eigentlich benutzt man dafür LAST_INSERT_ID(). Bei den MySQL-
Connectoren, die das unterstützen, gibts auch einen API-Call, der
diese Information aus dem ACK Paket vom MySQL Server bereitstellt.
Der ODBC-Connector gehört wohl leider nicht dazu.

>>> Nun funktioniert das ganze mittels Labview nicht, die Fehlermeldung
>>> suggeriert, daß der ODBC-Treiber nur ein SQL-Statement pro Abfrage
>>> zuläßt.
>>>
>>> Wie kann man das anders lösen?
>>
>> Wenn das wirklich die Ursache ist, dann hole doch die ID in einer 2.
>> Abfrage. Sie sollte sich ja nicht ändern für diese Session.
>
> Naja, das war ein Trivialbeispiel. Normalerweise wird ein Eintrag
> angelegt, der später mit Update bearbeitet wird. Mehrere Datenquellen
> erzeugen gleichzeitig (auch vom selben Client / Programm) die Einträge.

Solange die INSERTs über verschiedene MySQL-Connections reinkommen, ist
das kein Problem. Wenn du schon in deinem Programm mehrere Datenströme
auf eine MySQL-Verbindung multiplext, dann muß du halt selber dafür
sorgen, daß INSERT und SELECT in einem Rutsch ausgeführt werden.

Wesentlich sinnvoller wäre IMHO, jedem Datenstrom eine eigene MySQL-
Verbindung zu spendieren.

> Ich brauche also eine eindeutige ID, die entweder von der DB
> bereitgestellt wird, oder die ich erzeuge (Problem: wie) und mit der
> ich dann den jeweils gültigen Eintrag auswählen kann.

Einen Ansatz, wie man Sequenzen in MySQL emuliert, habe ich hier:
http://forge.mysql.com/snippets/view.php?id=7

mal aufgeschrieben. In der dort gezeigten Form hat das natürlich genau
das gleiche Problem wie LAST_INSERT_ID(). Allerdings kannst du den
Namen der Uservariablen für die Sequenznummer frei wählen. Wenn du da
irgendwie deine Datenstrom-ID reincodierst, dann kannst du Erzeugung
und Abfrage von Sequenznummern beliebig wild mischen.


XL

Re: Frage zu ODBC (Labview)

am 20.11.2006 15:37:00 von Thomas Rachel

Jan Schmidt wrote:

> weil ich nicht sicherstellen kann, daß nicht ein anderer Thread
> zwischen insert und select selbst ein insert absetzt (s.u.).

Wenn eine Anwendung, die mit Threads arbeitet, nicht pro Thread eine
eigene DB-Verbindung aufmacht, ist sie IMHO kaputt. Denn der eine Thread
kann nicht ohne weiteres wissen, ob es dem SQL-Programmablauf im anderen
Thread grad in den Kram paßt, wenn jetzt ein Query kommt, der mit dem
Rest nicht das Geringste zu tun hat.

Sollte es in Deinem Fall dennoch so sein: die API-Funktion
mysql_insert_id() und die SQL-Funktion last_insert_id() arbeiten leicht
unterschiedlich:

last_insert_id() ist abrufbar bis zum nächsten INSERT (oder sogar bis zum
nächsten INSERT mit AUTO_INCREMENT? Das kann ich mir nie merken.)

mysql_insert_id() ist hingegen nur bis zum nächsten Query abrufbar.


Hm, bei genauerer Überlegung hast Du bei beiden Funktionen u.U. eine
Race-Condition.

Nein, ohne separate Verbindungen pro Thread ist kein sauberes Arbeiten
möglich. Am besten checkst Du das vorher mal ab (mysqladmin processlist
ist Dein Freund), vielleicht besteht Dein Problem gar nicht...


Thomas
--
Jabber-ID: glglgl@amessage.info (keine Email-Adresse!)
Warum Jabber, was ist das und wie geht das?
http://de.wikibooks.org/wiki/Jabber-Kompendium:_Schnelleinst ieg

Re: Frage zu ODBC (Labview)

am 20.11.2006 16:51:15 von Jan Schmidt

Thomas Rachel writes:

> Jan Schmidt wrote:
>
>> weil ich nicht sicherstellen kann, daß nicht ein anderer Thread
>> zwischen insert und select selbst ein insert absetzt (s.u.).

> Nein, ohne separate Verbindungen pro Thread ist kein sauberes Arbeiten
> möglich. Am besten checkst Du das vorher mal ab (mysqladmin processlist
> ist Dein Freund), vielleicht besteht Dein Problem gar nicht...

Es werden verschiedene Prozesse angezeigt - danke für den Tip. Ich
teste das morgen mal obs tatsächlich funktioniert.

Gruß,
jan

Re: Frage zu ODBC (Labview)

am 20.11.2006 17:13:32 von Thomas Rachel

Jan Schmidt wrote:

> Thomas Rachel writes:

>> Nein, ohne separate Verbindungen pro Thread ist kein sauberes Arbeiten
>> möglich. Am besten checkst Du das vorher mal ab (mysqladmin
>> processlist ist Dein Freund), vielleicht besteht Dein Problem gar
>> nicht...
>
> Es werden verschiedene Prozesse angezeigt - danke für den Tip.

Na super. Also werden die IDs auch komplett getrennt voneinander
behandelt und Dein Problem sollte nicht wirklich bestehen.

Was Sachen wie Locking angeht, mußt Du Dir allerdings evtl. noch genau
anschauen...


Thomas
--
Jabber-ID: glglgl@amessage.info (keine Email-Adresse!)
Warum Jabber, was ist das und wie geht das?
http://de.wikibooks.org/wiki/Jabber-Kompendium:_Schnelleinst ieg