function crashes backend

From: Louis-David Mitterrand <cunctator(at)apartia(dot)ch>
To: pgsql-hackers(at)postgresql(dot)org
Subject: function crashes backend
Date: 2000-09-27 06:53:58
Message-ID: 20000927085358.A9646@styx
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello,

I am writing a SPI function to run maintenance tasks on my auction
system but it keeps crashing the backend after running only one loop.
Now, I am not a C programmer, nor do I have any formal training in CS. I
thought I might run this function by you guys so that a cursory look
might reveal some obvious coding mistake?

Thanks in advance for your insight.

int4 auction_maintenance(void) {

char * query, * default_locale = getenv("LC_ALL");
bool current, isnull;
int i;

/* Connect to SPI manager
*/
if (SPI_connect() != SPI_OK_CONNECT)
elog(ERROR, "bid_control.c: SPI_connect failed");

/* asprintf(&query, "BEGIN");
SPI_exec(query, 0);
free(query);*/

/* check if last modification time of special user id 0 is less than 15
* minutes ago
*/
asprintf(&query, "SELECT ((now()::abstime::int4 - modified::abstime::int4) \
/ 60) < 15 AS current FROM person WHERE id = 0 FOR UPDATE");
SPI_exec(query, 0);
free(query);

current = DatumGetChar(SPI_getbinval(
SPI_tuptable->vals[0], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "current"), &isnull));

if (current) {
/* maintenance script ran less that 15 minutes ago, do nothing
*/
/* asprintf(&query, "COMMIT");
SPI_exec(query, 0);
free(query);*/

elog(NOTICE, "auction system still current");

SPI_finish();
return current;
}

/* update modification time now, locking other daemons out
*/
asprintf(&query, "UPDATE person SET modified = now() WHERE id = 0");
SPI_exec(query, 0);
free(query);

/* asprintf(&query, "COMMIT");
SPI_exec(query, 0);
free(query);*/

/* start real mainenance work here
*/

/* asprintf(&query, "BEGIN");
SPI_exec(query, 0);
free(query);*/

/* select all auctions that have expired and have not been notified
*/
asprintf(&query, "SELECT *,auction_status(a.id), \
seller.mail AS seller_mail, seller.locale AS seller_locale, \
seller.login AS seller_login \
FROM auction a, person seller WHERE auction_status(a.id) <= 0 \
AND a.person_id = seller.id \
AND (notified IS FALSE OR notified IS NULL) FOR UPDATE");
SPI_exec(query, 0);
free(query);

for (i = SPI_processed - 1; i >= 0; i--) {

int type = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "type"), &isnull));

char * title = SPI_getvalue(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "title"));

char * seller_mail = SPI_getvalue(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "seller_mail"));

char * seller_locale = SPI_getvalue(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "seller_locale"));

char * seller_login = SPI_getvalue(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "seller_login"));

char * stopdate = SPI_getvalue(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "stopdate"));

int auction_id = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "id"), &isnull));

int lot = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "lot"), &isnull));

int auction_status = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "auction_status"), &isnull));

int renew_count = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "renew_count"), &isnull));

/* bool auto_renew = DatumGetChar(SPI_getbinval(
SPI_tuptable->vals[i], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "auto_renew"), &isnull));*/

elog(NOTICE, "Processing auction #%d of %d (\n"
"type: %d\n"
"title: %s\n"
"seller_mail: %s\n"
"seller_locale: %s\n"
"seller_login: %s\n"
"stopdate: %s\n"
"id: %d\n"
"lot: %d\n"
"status: %d\n"
"renew_count: %d\n"
")",
SPI_processed - i, SPI_processed,
type,
title,
seller_mail,
seller_locale,
seller_login,
stopdate,
auction_id,
lot,
auction_status,
renew_count
);

/* FIRST, store a copy of this auction in the archive, before eventually
* running UPDATE or DELETE on it
*/
asprintf(&query, "INSERT INTO auction_archive SELECT * FROM auction \
WHERE id = %d", auction_id);
SPI_exec(query, 0);
free(query);

/* store a copy of all bids into archive
*/
asprintf(&query, "INSERT INTO bid_archive SELECT * FROM bid \
WHERE auction_id = %d", auction_id);
SPI_exec(query, 0);
free(query);
/*#if 0*/
/* winner/seller notification
*/
if (auction_status != -lot) { /* something was sold */
char * mess;
char **bidder_login, **bidder_mail, **bidder_locale;
int *bid_lot, *bidder_id, j, l;
double *bid_price;

/* get high bidders
*/
asprintf(&query, "SELECT max(b.lot) AS bid_lot, \
max(b.price) AS bid_price,p.login AS bidder_login, \
p.id AS bidder_id, p.mail AS bidder_mail, \
p.locale AS bidder_locale \
FROM bid b, person p \
WHERE b.auction_id = %d AND p.id = b.person_id \
GROUP BY p.login, p.id, p.mail,p.locale \
ORDER BY max(price)", auction_id);
SPI_exec(query, 0);
free(query);

bid_price = alloca(SPI_processed * sizeof(double));
bid_lot = alloca(SPI_processed * sizeof(int));
bidder_id = alloca(SPI_processed * sizeof(int));

bidder_login = alloca(SPI_processed * sizeof(char*));
bidder_mail = alloca(SPI_processed * sizeof(char*));
bidder_locale = alloca(SPI_processed * sizeof(char*));

/* elog(NOTICE, "starting winner/seller notification on auction #%d",
auction_id);*/

/* get winner list
*/
for (j = SPI_processed - 1; j >= 0; j--) {
bid_price[j] = *DatumGetFloat64(SPI_getbinval(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bid_price"),
&isnull));

bid_lot[j] = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bid_lot"),
&isnull));

bidder_id[j] = DatumGetInt32(SPI_getbinval(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bidder_id"),
&isnull));

bidder_login[j] = SPI_getvalue(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bidder_login"));

bidder_mail[j] = SPI_getvalue(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bidder_mail"));

bidder_locale[j] = SPI_getvalue(
SPI_tuptable->vals[j], SPI_tuptable->tupdesc,
SPI_fnumber(SPI_tuptable->tupdesc, "bidder_locale"));

elog(NOTICE, "extracting winner %s for price %f and lot %d",
bidder_login[j], bid_price[j], bid_lot[j]);
/* decrease available quantity marker until all is sold, dutch
* auctions only
*/
/* l -= bid_lot[i];*/

}

if (type == AUCTION_CLASSIC) {
char * winner = NULL;
double final_price;
/* winner = astrcat();*/
/* determine final_price for dutch auction: the lowest of the
* winning bids
*/
for (j = SPI_processed - 1, l = lot; j >= 0 && l > 0;
j--, l -= bid_lot[j]) {
final_price = bid_price[j];
}
for (j = SPI_processed - 1, l = lot; j >= 0 && l > 0;
j--, l -= bid_lot[j]) {

/* start building the string listing winners (for dutch)
* or the only winner (for normal)
*/
setlocale(LC_ALL, seller_locale);
setenv("LC_ALL", seller_locale, 1);

asprintf(&mess, _(
"* login: %s, \t"
"e-mail: %s, \t"
"bid price: %.2f, \t"
"bid quantity: %d, \t"
"final price: %.2f,\t"
"alloted quantity: %d,\t"
),
bidder_login[j], bidder_mail[j], bid_price[j],
bid_lot[j], final_price,
(bid_lot[j] < l ? l : bid_lot[j]) );
astrcat(&winner, mess);
free(mess);

elog(NOTICE, "winner #%d is %s", j, winner);

setlocale(LC_ALL, bidder_locale[j]);
setenv("LC_ALL", bidder_locale[j], 1);
/* notify winner directly
*/
asprintf(&mess, _(
"\tDear %s,\n"
"\n"
"On the following closed auction:"
"\n"
"- title: %s\n"
"- id: %d\n"
"- end date: %s\n"
"- seller: %s\n"
"- seller e-mail: %s\n"
"\n"
"You have entered this winning bid:\n"
"\n"
"- bid price: %.2f\n"
"- bid quantity: %d\n"
"- final price: %.2f\n"
"- alloted quantity: %d\n"
"\n"
"Please contact the seller as soon as possible to close the transaction\n"
"\n"
"-- \n"
"Apartia auction daemon\n"
), bidder_login[j], title,
auction_id, stopdate, seller_login, seller_mail,
bid_price[j], bid_lot[j], final_price,
(bid_lot[j] < l ? l : bid_lot[j]));
sendmail(bidder_mail[j], "Auction win notification", mess);
free(mess);

/* decrease available quantity marker until all is sold,
* dutch auctions only
*/
l -= bid_lot[j];
}

/* now notify the seller with a list of winning bids
*/
asprintf(&mess, _(
"\tDear %s,\n"
"\n"
"On your closed auction:\n"
"\n"
"- title: %s\n"
"- id: %d\n"
"- end date: %s\n"
"\n"
"The following winning bid(s) have been placed:\n"
"%s\n"
"\n"
"Please contact the winner(s) as soon as possible to close the transaction\n"
"-- \n"
"Apartia auction daemon\n"),
seller_login, title, auction_id, stopdate, winner
);
free(winner);
sendmail(seller_mail,
_("Auction successful close notification"), mess);
free(mess);

} else if (type == AUCTION_REVERSE || type == AUCTION_FIXED) {
} else if (type == AUCTION_BID) {
}

/* clean up memory
*/
/* free(bid_price);
free(bid_lot);
free(bidder_mail);
free(bidder_login);
free(bidder_locale);
free(bidder_id);*/
}

/* DELETE all old bids
*/
asprintf(&query, "DELETE FROM bid WHERE auction_id = %d",
auction_id);
SPI_exec(query, 0);
free(query);

asprintf(&query, "DELETE FROM autobid WHERE auction_id = %d",
auction_id);
SPI_exec(query, 0);
free(query);

/* renew expired auctions with unsold lots
*/
if (auction_status < 0 && renew_count > 0) {
asprintf(&query, "UPDATE auction SET startdate = now(), \
stopdate = now() + (stopdate - startdate), \
renew_count = renew_count - 1, \
lot = -auction_status(id), notified = FALSE, \
WHERE id = %d", auction_id);
SPI_exec(query, 0);
free(query);

/* localize message, numbers, dates
*/
setlocale(LC_ALL, seller_locale);
setenv("LC_ALL", seller_locale, 1);

/* notify seller of renewal
*/
asprintf(&query, _(
"\tDear %s\n"
"\n"
"Your expired auction:\n"
"- title: %s\n"
"- id: %d\n"
"- end date: %s\n"
"\n"
"has been auto-renewed today with the same duration.\n"
"\n"
"Greetings\n"
"-- \n"
"The auction daemon\n"
), seller_login, title, auction_id, stopdate);
sendmail(seller_mail, _("Auction renewal notice"), query);
free(query);
} else {

/* auction was closed and fully sold OR not auto_renewed,
*/
asprintf(&query, "DELETE FROM auction WHERE id = %d", auction_id);
SPI_exec(query, 0);
free(query);

/* only notify if nothing was sold; when something has been sold
* normal winner/seller notification has already taken place
* higher in this code
*/
if (auction_status == -lot) {
setlocale(LC_ALL, seller_locale);
setenv("LC_ALL", seller_locale, 1);
/* notify seller of auction end
*/
asprintf(&query, _(
"\tDear %s\n"
"\n"
"Your expired auction:\n"
"- title: %s\n"
"- id: %d\n"
"- end date: %s\n"
"\n"
"Has been removed from the system.\n"
"\n"
"-- \n"
"The auction daemon\n"
), seller_login, title, auction_id, stopdate);
sendmail(seller_mail, _("Auction expiration notice"), query);
free(query);
}
}
/*#endif*/
elog(NOTICE, "End of loop %d", i);
}

/* restore default locale
*/
setlocale(LC_ALL, default_locale);
setenv("LC_ALL", default_locale, 1);

/* asprintf(&query, "COMMIT");
SPI_exec(query, 0);
free(query);*/

SPI_finish();
return current;
}

--
Louis-David Mitterrand - ldm(at)apartia(dot)org - http://www.apartia.org

Radioactive cats have 18 half-lives.

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Hiroshi Inoue 2000-09-27 07:23:19 Re: libpq static link library dowsn't work (M$ VS6)
Previous Message Hannu Krosing 2000-09-27 06:41:18 Re: pgsql is 75 times faster with my new index scan