function buy_stock($symb, $comment = '', $volume = 0)
{
    // moves stock from the cart to trades and updates pf_summary
    global $db_hostname, $db_database, $db_user, $db_password;
    $portfolio = new portfolio($_SESSION['pfid']);
    $pfid = $portfolio->getID();
    $date = $portfolio->getWorkingDate();
    $exch = $portfolio->getExch()->getID();
    $commission = $portfolio->getCommission();
    $close = get_stock_close($symb, $date, $exch);
    if ($comment == '') {
        $comment = "{$name}: {$date}";
    }
    if ($volume != 0) {
        $qty = $volume;
    } else {
        // this means that a volume of '0' buys one parcel's worth.
        // is that what we want?
        if ($close < $parcel) {
            $qty = (int) ($parcel / $close);
        } else {
            $qty = 1;
        }
    }
    // take the absolute value of $qty since we set aside the purchase price as an asset for a short.
    $total = $close * abs($qty);
    try {
        $pdo = new PDO("pgsql:host={$db_hostname};dbname={$db_database}", $db_user, $db_password);
        $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    } catch (PDOException $e) {
        die("ERROR: Cannot connect: " . $e->getMessage());
    }
    // find out how much money, and stocks are in the portfolio today
    $query = "select cash_in_hand, holdings from pf_summary where pfid = '{$pfid}' and date = '{$date}';";
    foreach ($pdo->query($query) as $row) {
        $cash_in_hand = $row['cash_in_hand'];
        $holdings = $row['holdings'];
    }
    $duty = $total * ($portfolio->getTaxRate() / 100);
    if ($cash_in_hand < $total + $duty + $commission) {
        // we can't afford this one!
        return false;
    }
    $cash_in_hand = $cash_in_hand - $total - $duty - $commission;
    $holdings = $holdings + $total;
    try {
        $query = "select nextval('trades_trid_seq') as trid;";
        $result = $pdo->query($query);
        $row = $result->fetch(PDO::FETCH_ASSOC);
        $next_trid = $row['trid'];
    } catch (PDOException $e) {
        tr_warn('buy_stock:' . $query . ':' . $e->getMessage());
        return false;
    }
    try {
        $query = "select nextval('holdings_hid_seq') as hid;";
        $result = $pdo->query($query);
        $row = $result->fetch(PDO::FETCH_ASSOC);
        $next_hid = $row['hid'];
    } catch (PDOException $e) {
        tr_warn('buy_stock:' . $query . ':' . $e->getMessage());
        return false;
    }
    try {
        $pdo->beginTransaction();
        // add the trade to the trades table
        $query = "insert into trades (trid, pfid, hid, date, symb, price, volume, comment, tr_type) values ('{$next_trid}', '{$pfid}', '{$next_hid}', '{$date}', '{$symb}', '{$close}', '{$qty}', '{$comment}', 'O');";
        $pdo->exec($query);
        // add the transaction to the holdings table
        $query = "insert into holdings (hid, pfid, date, symb, price, volume, comment) values ('{$next_hid}', '{$pfid}', '{$date}', '{$symb}', '{$close}', '{$qty}', '{$comment}');";
        $pdo->exec($query);
        // update the pf_summary with the trade
        $query = "update pf_summary set cash_in_hand = '{$cash_in_hand}', holdings = '{$holdings}' where date = '{$date}' and pfid = '{$pfid}';";
        $pdo->exec($query);
        $pdo->commit();
    } catch (PDOException $e) {
        $pdo->rollBack();
        tr_warn('buy_stock:' . $query . ':' . $e->getMessage());
        return false;
    }
    return true;
}