11/*
22 *PostgreSQL type definitions for the INET and CIDR types.
33 *
4- *$PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/1103:32:39 momjian Exp $
4+ *$PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.65 2006/02/1120:39:58 tgl Exp $
55 *
66 *Jon Postel RIP 16 Oct 1998
77 */
@@ -27,7 +27,7 @@ static int32 network_cmp_internal(inet *a1, inet *a2);
2727static int bitncmp (void * l ,void * r ,int n );
2828static bool addressOK (unsignedchar * a ,int bits ,int family );
2929static int ip_addrsize (inet * inetptr );
30- static Datum internal_inetpl (inet * ip ,int64 iarg );
30+ static inet * internal_inetpl (inet * ip ,int64 addend );
3131
3232/*
3333 *Access macros.
@@ -1292,8 +1292,7 @@ inetand(PG_FUNCTION_ARGS)
12921292if (ip_family (ip )!= ip_family (ip2 ))
12931293ereport (ERROR ,
12941294(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1295- errmsg ("mismatch in address family (%d) != (%d)" ,
1296- ip_family (ip ),ip_family (ip2 ))));
1295+ errmsg ("cannot AND inet values of different sizes" )));
12971296else
12981297{
12991298int nb = ip_addrsize (ip );
@@ -1327,8 +1326,7 @@ inetor(PG_FUNCTION_ARGS)
13271326if (ip_family (ip )!= ip_family (ip2 ))
13281327ereport (ERROR ,
13291328(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1330- errmsg ("mismatch in address family (%d) != (%d)" ,
1331- ip_family (ip ),ip_family (ip2 ))));
1329+ errmsg ("cannot OR inet values of different sizes" )));
13321330else
13331331{
13341332int nb = ip_addrsize (ip );
@@ -1350,8 +1348,8 @@ inetor(PG_FUNCTION_ARGS)
13501348}
13511349
13521350
1353- static Datum
1354- internal_inetpl (inet * ip ,int64 plus )
1351+ static inet *
1352+ internal_inetpl (inet * ip ,int64 addend )
13551353{
13561354inet * dst ;
13571355
@@ -1365,15 +1363,31 @@ internal_inetpl(inet *ip, int64 plus)
13651363
13661364while (nb -- > 0 )
13671365{
1368- pdst [nb ]= carry = pip [nb ]+ plus + carry ;
1369- plus /=0x100 ;/* process next byte */
1370- carry /=0x100 ;/* remove low byte */
1371- /* Overflow on high byte? */
1372- if (nb == 0 && (plus != 0 || carry != 0 ))
1373- ereport (ERROR ,
1374- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1375- errmsg ("result out of range" )));
1366+ carry = pip [nb ]+ (int ) (addend & 0xFF )+ carry ;
1367+ pdst [nb ]= (unsignedchar ) (carry & 0xFF );
1368+ carry >>=8 ;
1369+ /*
1370+ * We have to be careful about right-shifting addend because
1371+ * right-shift isn't portable for negative values, while
1372+ * simply dividing by 256 doesn't work (the standard rounding
1373+ * is in the wrong direction, besides which there may be machines
1374+ * out there that round the wrong way). So, explicitly clear
1375+ * the low-order byte to remove any doubt about the correct
1376+ * result of the division, and then divide rather than shift.
1377+ */
1378+ addend &= ~((int64 )0xFF );
1379+ addend /=0x100 ;
13761380}
1381+ /*
1382+ * At this point we should have addend and carry both zero if
1383+ * original addend was >= 0, or addend -1 and carry 1 if original
1384+ * addend was < 0. Anything else means overflow.
1385+ */
1386+ if (!((addend == 0 && carry == 0 )||
1387+ (addend == -1 && carry == 1 )))
1388+ ereport (ERROR ,
1389+ (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1390+ errmsg ("result out of range" )));
13771391}
13781392ip_bits (dst )= ip_bits (ip );
13791393
@@ -1382,27 +1396,27 @@ internal_inetpl(inet *ip, int64 plus)
13821396((char * )ip_addr (dst )- (char * )VARDATA (dst ))+
13831397ip_addrsize (dst );
13841398
1385- PG_RETURN_INET_P ( dst ) ;
1399+ return dst ;
13861400}
13871401
13881402
13891403Datum
13901404inetpl (PG_FUNCTION_ARGS )
13911405{
13921406inet * ip = PG_GETARG_INET_P (0 );
1393- int64 plus = PG_GETARG_INT64 (1 );
1407+ int64 addend = PG_GETARG_INT64 (1 );
13941408
1395- return internal_inetpl (ip ,plus );
1409+ PG_RETURN_INET_P ( internal_inetpl (ip ,addend ) );
13961410}
13971411
13981412
13991413Datum
14001414inetmi_int8 (PG_FUNCTION_ARGS )
14011415{
14021416inet * ip = PG_GETARG_INET_P (0 );
1403- int64 plus = PG_GETARG_INT64 (1 );
1417+ int64 addend = PG_GETARG_INT64 (1 );
14041418
1405- return internal_inetpl (ip ,- plus );
1419+ PG_RETURN_INET_P ( internal_inetpl (ip ,- addend ) );
14061420}
14071421
14081422
@@ -1416,42 +1430,53 @@ inetmi(PG_FUNCTION_ARGS)
14161430if (ip_family (ip )!= ip_family (ip2 ))
14171431ereport (ERROR ,
14181432(errcode (ERRCODE_INVALID_PARAMETER_VALUE ),
1419- errmsg ("mismatch in address family (%d) != (%d)" ,
1420- ip_family (ip ),ip_family (ip2 ))));
1433+ errmsg ("cannot subtract inet values of different sizes" )));
14211434else
14221435{
1436+ /*
1437+ * We form the difference using the traditional complement,
1438+ * increment, and add rule, with the increment part being handled
1439+ * by starting the carry off at 1. If you don't think integer
1440+ * arithmetic is done in two's complement, too bad.
1441+ */
14231442int nb = ip_addrsize (ip );
14241443int byte = 0 ;
14251444unsignedchar * pip = ip_addr (ip );
14261445unsignedchar * pip2 = ip_addr (ip2 );
1446+ int carry = 1 ;
14271447
14281448while (nb -- > 0 )
14291449{
1430- /*
1431- *Error if overflow on last byte. This test is tricky
1432- *because if the subtraction == 128 and res is negative, or
1433- *if subtraction == -128 and res is positive, the result
1434- *would still fit in int64.
1435- */
1436- if (byte + 1 == sizeof (int64 )&&
1437- (pip [nb ]- pip2 [nb ] >=128 + (res < 0 )||
1438- pip [nb ]- pip2 [nb ] <=-128 - (res > 0 )))
1439- ereport (ERROR ,
1440- (errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1441- errmsg ("result out of range" )));
1442- if (byte >=sizeof (int64 ))
1450+ int lobyte ;
1451+
1452+ carry = pip [nb ]+ (~pip2 [nb ]& 0xFF )+ carry ;
1453+ lobyte = carry & 0xFF ;
1454+ if (byte < sizeof (int64 ))
14431455{
1444- /* Error if bytes beyond int64 length differ. */
1445- if (pip [nb ]!= pip2 [nb ])
1456+ res |= ((int64 )lobyte ) << (byte * 8 );
1457+ }
1458+ else
1459+ {
1460+ /*
1461+ * Input wider than int64: check for overflow. All bytes
1462+ * to the left of what will fit should be 0 or 0xFF,
1463+ * depending on sign of the now-complete result.
1464+ */
1465+ if ((res < 0 ) ? (lobyte != 0xFF ) : (lobyte != 0 ))
14461466ereport (ERROR ,
14471467(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
14481468errmsg ("result out of range" )));
14491469}
1450- else
1451- res += (int64 )(pip [nb ]- pip2 [nb ]) << (byte * 8 );
1452-
1470+ carry >>=8 ;
14531471byte ++ ;
14541472}
1473+
1474+ /*
1475+ * If input is narrower than int64, overflow is not possible, but
1476+ * we have to do proper sign extension.
1477+ */
1478+ if (carry == 0 && byte < sizeof (int64 ))
1479+ res |= ((int64 )- 1 ) << (byte * 8 );
14551480}
14561481
14571482PG_RETURN_INT64 (res );