1
1
/*
2
2
* PostgreSQL type definitions for the INET and CIDR types.
3
3
*
4
- * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.64 2006/02/11 03:32:39 momjian Exp $
4
+ * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.65 2006/02/11 20:39:58 tgl Exp $
5
5
*
6
6
* Jon Postel RIP 16 Oct 1998
7
7
*/
@@ -27,7 +27,7 @@ static int32 network_cmp_internal(inet *a1, inet *a2);
27
27
static int bitncmp (void * l , void * r , int n );
28
28
static bool addressOK (unsigned char * a , int bits , int family );
29
29
static int ip_addrsize (inet * inetptr );
30
- static Datum internal_inetpl (inet * ip , int64 iarg );
30
+ static inet * internal_inetpl (inet * ip , int64 addend );
31
31
32
32
/*
33
33
* Access macros.
@@ -1292,8 +1292,7 @@ inetand(PG_FUNCTION_ARGS)
1292
1292
if (ip_family (ip ) != ip_family (ip2 ))
1293
1293
ereport (ERROR ,
1294
1294
(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" )));
1297
1296
else
1298
1297
{
1299
1298
int nb = ip_addrsize (ip );
@@ -1327,8 +1326,7 @@ inetor(PG_FUNCTION_ARGS)
1327
1326
if (ip_family (ip ) != ip_family (ip2 ))
1328
1327
ereport (ERROR ,
1329
1328
(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" )));
1332
1330
else
1333
1331
{
1334
1332
int nb = ip_addrsize (ip );
@@ -1350,8 +1348,8 @@ inetor(PG_FUNCTION_ARGS)
1350
1348
}
1351
1349
1352
1350
1353
- static Datum
1354
- internal_inetpl (inet * ip , int64 plus )
1351
+ static inet *
1352
+ internal_inetpl (inet * ip , int64 addend )
1355
1353
{
1356
1354
inet * dst ;
1357
1355
@@ -1365,15 +1363,31 @@ internal_inetpl(inet *ip, int64 plus)
1365
1363
1366
1364
while (nb -- > 0 )
1367
1365
{
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 ] = (unsigned char ) (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 ;
1376
1380
}
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" )));
1377
1391
}
1378
1392
ip_bits (dst ) = ip_bits (ip );
1379
1393
@@ -1382,27 +1396,27 @@ internal_inetpl(inet *ip, int64 plus)
1382
1396
((char * ) ip_addr (dst ) - (char * ) VARDATA (dst )) +
1383
1397
ip_addrsize (dst );
1384
1398
1385
- PG_RETURN_INET_P ( dst ) ;
1399
+ return dst ;
1386
1400
}
1387
1401
1388
1402
1389
1403
Datum
1390
1404
inetpl (PG_FUNCTION_ARGS )
1391
1405
{
1392
1406
inet * ip = PG_GETARG_INET_P (0 );
1393
- int64 plus = PG_GETARG_INT64 (1 );
1407
+ int64 addend = PG_GETARG_INT64 (1 );
1394
1408
1395
- return internal_inetpl (ip , plus );
1409
+ PG_RETURN_INET_P ( internal_inetpl (ip , addend ) );
1396
1410
}
1397
1411
1398
1412
1399
1413
Datum
1400
1414
inetmi_int8 (PG_FUNCTION_ARGS )
1401
1415
{
1402
1416
inet * ip = PG_GETARG_INET_P (0 );
1403
- int64 plus = PG_GETARG_INT64 (1 );
1417
+ int64 addend = PG_GETARG_INT64 (1 );
1404
1418
1405
- return internal_inetpl (ip , - plus );
1419
+ PG_RETURN_INET_P ( internal_inetpl (ip , - addend ) );
1406
1420
}
1407
1421
1408
1422
@@ -1416,42 +1430,53 @@ inetmi(PG_FUNCTION_ARGS)
1416
1430
if (ip_family (ip ) != ip_family (ip2 ))
1417
1431
ereport (ERROR ,
1418
1432
(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" )));
1421
1434
else
1422
1435
{
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
+ */
1423
1442
int nb = ip_addrsize (ip );
1424
1443
int byte = 0 ;
1425
1444
unsigned char * pip = ip_addr (ip );
1426
1445
unsigned char * pip2 = ip_addr (ip2 );
1446
+ int carry = 1 ;
1427
1447
1428
1448
while (nb -- > 0 )
1429
1449
{
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 ))
1443
1455
{
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 ))
1446
1466
ereport (ERROR ,
1447
1467
(errcode (ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE ),
1448
1468
errmsg ("result out of range" )));
1449
1469
}
1450
- else
1451
- res += (int64 )(pip [nb ] - pip2 [nb ]) << (byte * 8 );
1452
-
1470
+ carry >>= 8 ;
1453
1471
byte ++ ;
1454
1472
}
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 );
1455
1480
}
1456
1481
1457
1482
PG_RETURN_INT64 (res );
0 commit comments