Subject | Re: [Firebird-Architect] Re: Replace the statement REPLACE |
---|---|
Author | Jim Starkey |
Post date | 2006-11-22T15:03:25Z |
Lester Caine wrote:
(inaccessible from MySQL) first fetches the record. If it finds a
record, it updates it, otherwise it does an insert. Code follows (note:
the insert inside of the catch statement is purely for debugging):
void NReplace::evalStatement(Statement *statement)
{
if (select)
{
select->evalStatement (statement);
ResultSet *resultSet = statement->getResultSet();
while (resultSet->next())
doReplace (statement, resultSet);
}
else
doReplace (statement, NULL);
}
void NReplace::doReplace(Statement *statement, ResultSet *resultSet)
{
statement->updateStatements = true;
Value **values = new Value* [numberFields];
try
{
Transaction *transaction = statement->transaction;
int n;
// Compute values for fields
for (n = 0; n < numberFields; ++n)
if (resultSet)
values [n] = resultSet->getValue (n + 1);
else
values [n] = children [n]->eval (statement);
// See if we fetch a record. If not, do an insert
stream->open (statement);
if (!stream->fetch (statement))
{
stream->close (statement);
try
{
table->insert (statement->transaction, numberFields,
fields, values);
}
catch (...)
{
stream->open(statement);
stream->fetch(statement);
stream->close(statement);
table->insert (statement->transaction, numberFields,
fields, values);
}
++statement->stats.inserts;
++statement->stats.replaces;
++statement->recordsUpdated;
delete [] values;
return;
}
Context *context = statement->getContext (contextId);
Record *record = context->record;
bool diff = false;
// Check for any differences. If not, it's a no-op
for (n = 0; n < numberFields; ++n)
if (!diff)
{
Value value;
record->getValue (fields [n]->id, &value);
if (value.compare (values [n]) != 0)
{
diff = true;
break;
}
}
// If anything changed, update the record
if (diff)
{
table->update (transaction, context->record, numberFields,
fields, values);
++statement->stats.updates;
++statement->stats.replaces;
++statement->recordsUpdated;
}
stream->close (statement);
delete [] values;
return;
}
catch (...)
{
delete [] values;
throw;
}
}
> Adam wrote:Rather than trying either statement, the internal Falcon engine
>
>> Running an update which affects 0 rows would not fire any update trigger.
>>
>> So if it tried insert then update:
>>
>> Before insert trigger -> attempt insert -> fails -> before update
>> trigger -> update -> after update trigger.
>>
>> Or if it tried update and insert:
>>
>> The update wouldn't affect any row, so no update triggers are fired,
>> therefore the insert is attempted.
>>
>> So depending on the methodology chosen, the before insert triggers may
>> be fired.
>>
>
> Good pickup Adam - I knew there was a reason I try the update first ;)
>
>
(inaccessible from MySQL) first fetches the record. If it finds a
record, it updates it, otherwise it does an insert. Code follows (note:
the insert inside of the catch statement is purely for debugging):
void NReplace::evalStatement(Statement *statement)
{
if (select)
{
select->evalStatement (statement);
ResultSet *resultSet = statement->getResultSet();
while (resultSet->next())
doReplace (statement, resultSet);
}
else
doReplace (statement, NULL);
}
void NReplace::doReplace(Statement *statement, ResultSet *resultSet)
{
statement->updateStatements = true;
Value **values = new Value* [numberFields];
try
{
Transaction *transaction = statement->transaction;
int n;
// Compute values for fields
for (n = 0; n < numberFields; ++n)
if (resultSet)
values [n] = resultSet->getValue (n + 1);
else
values [n] = children [n]->eval (statement);
// See if we fetch a record. If not, do an insert
stream->open (statement);
if (!stream->fetch (statement))
{
stream->close (statement);
try
{
table->insert (statement->transaction, numberFields,
fields, values);
}
catch (...)
{
stream->open(statement);
stream->fetch(statement);
stream->close(statement);
table->insert (statement->transaction, numberFields,
fields, values);
}
++statement->stats.inserts;
++statement->stats.replaces;
++statement->recordsUpdated;
delete [] values;
return;
}
Context *context = statement->getContext (contextId);
Record *record = context->record;
bool diff = false;
// Check for any differences. If not, it's a no-op
for (n = 0; n < numberFields; ++n)
if (!diff)
{
Value value;
record->getValue (fields [n]->id, &value);
if (value.compare (values [n]) != 0)
{
diff = true;
break;
}
}
// If anything changed, update the record
if (diff)
{
table->update (transaction, context->record, numberFields,
fields, values);
++statement->stats.updates;
++statement->stats.replaces;
++statement->recordsUpdated;
}
stream->close (statement);
delete [] values;
return;
}
catch (...)
{
delete [] values;
throw;
}
}