inicio mail me! sindicaci;ón

Archive for Mai, 2009

Du bist Terrorist.

Kampagne gegen Terroristen in Deutschland. Sehr schön.

Atomares Einfügen in PostgreSQL

Oft steht man vor dem Problem, einen Datensatz anhand eines Kriteriums zu finden bzw. ihn, falls nicht vorhanden, einzufügen. Bei derartigen Operationen ist es wichtig darauf zu achten, dass nicht mehrere Prozesse, die quasi gleichzeitig diesen Datensatz suchen, eine race condition hervorrufen.
Hier eine Lösung mittels stored procedure für postgresql. Dabei wird eine race condition zwischen Suche und Einfügen vermieden und nur minimales Locking gebraucht:

CREATE OR REPLACE FUNCTION findOrCreate(
  IN criterion_in text, 
  OUT id int, OUT is_new bool) AS 
$$
DECLARE 
BEGIN
  LOCK TABLE my_table;
  SELECT false, id FROM my_table WHERE criterion=criterion_in INTO is_new, id;

  IF id IS NULL THEN
    INSERT INTO 
      my_table (criterion) 
    VALUES 
      (criterion_in) 
    RETURNING id INTO id;
    
    SELECT true INTO is_new;
  END IF;

  RETURN;
END
$$ language plpgsql;

Man beachte die praktischen OUT-Parameter, die es ermöglichen, diese Funktion wie folgt aufzurufen:

SELECT id, is_new FROM findOrCreate(criterion);

Rückgabewerte sind id und is_new, die einem die Datenbank-Id angeben, und ob diese neu angelegt wurde.

Der Table-Lock wird beim Beenden der Funktion (die immer implizit eine Transaktion ist) automatisch beendet.

What ist this?

Laut PHP-Doku ist das Verhalten der Pseudo-Variablen $this wie folgt:

$this is a reference to the calling object (usually the object to which the method belongs, but can be another object, if the method is called statically from the context of a secondary object).

Schauen wir uns folgendes Beispiel an:

class A{
  function __construct(){
    $this->name = 'A';
  }

  function echoThisName(){
    echo "My Name is {$this->name}.\n";
  }
}

Jetzt rufen wir die Methode mal als Instanzmethode und mal statisch auf:

$a = new A();
$a->echoThisName();
A::echoThisName();


My Name is A.
PHP Fatal error:  Using $this when not in object context in 
/Users/aljoscha/test.php on line 9
Fatal error: Using $this when not in object context in 
/Users/aljoscha/test.php on line 9

Das ist vernünftig. (ausser: Warum muss sich PHP eigentlich immer wiederholen? Ist eine Fehlermeldung zu subtil?)
Jetzt rufen wird diese Methoden aus einer anderen Klasse B heraus auf:

class B{
  function __construct(){
    $this->name = 'B';
  }

  function echoAsName(){
    $a = new A();
    $a->echoThisName();
    A::echoThisName();
  }
}

$b = new B();
$b->echoAsName();

Und das gibt:

My Name is A.
My Name is B.

Wir haben die Methode echoThisName der Klasse A statisch aufgerufen, aber $this ist darin trotzdem gesetzt, und zwar als wären wir in der Instanz $b der Klasse B.
$b hat sich die statische Methode gekapert.

Was sagt Ruby dazu?


class A
  def initialize
    @name = 'A';
  end

  def echoThisName
    puts "My Name is #{@name}.\n";
  end
end

$a = A.new;
$a.echoThisName;
A::echoThisName;

ergibt:


My Name is A.
test.rb:13: undefined method `echoThisName' for A:Class (NoMethodError)

Rufen wir A::echoThisName aus einer Instanz von B auf:


class B
  def initialize
    @name = 'B';
  end

  def echoAsName
    $a = A.new;
    $a.echoThisName;
    A::echoThisName;
  end
end

$b = B.new;
$b.echoAsName;

Ist das Ergebnis entsprechend:

My Name is A.
test.rb:23:in `echoAsName': undefined method `echoThisName' 
for A:Class (NoMethodError) from test.rb:28

Besser.
Dank an Stephan für den Hinweis auf die Dokumentation des Verhaltens in PHP.