|
8 | 8 | * |
9 | 9 | * |
10 | 10 | * IDENTIFICATION |
11 | | - * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.53 2000/12/03 14:51:01 thomas Exp $ |
| 11 | + * $Header: /cvsroot/pgsql/src/backend/utils/adt/date.c,v 1.54 2000/12/07 18:38:59 tgl Exp $ |
12 | 12 | * |
13 | 13 | *------------------------------------------------------------------------- |
14 | 14 | */ |
@@ -529,37 +529,122 @@ time_smaller(PG_FUNCTION_ARGS) |
529 | 529 | PG_RETURN_TIMEADT((time1<time2) ?time1 :time2); |
530 | 530 | } |
531 | 531 |
|
532 | | -/* overlaps_time() |
533 | | - * Implements the SQL92 OVERLAPS operator. |
534 | | - * Algorithm from Date and Darwen, 1997 |
| 532 | +/* overlaps_time() --- implements the SQL92 OVERLAPS operator. |
| 533 | + * |
| 534 | + * Algorithm is per SQL92 spec. This is much harder than you'd think |
| 535 | + * because the spec requires us to deliver a non-null answer in some cases |
| 536 | + * where some of the inputs are null. |
535 | 537 | */ |
536 | 538 | Datum |
537 | 539 | overlaps_time(PG_FUNCTION_ARGS) |
538 | 540 | { |
539 | | -TimeADTts1=PG_GETARG_TIMEADT(0); |
540 | | -TimeADTte1=PG_GETARG_TIMEADT(1); |
541 | | -TimeADTts2=PG_GETARG_TIMEADT(2); |
542 | | -TimeADTte2=PG_GETARG_TIMEADT(3); |
| 541 | +/* The arguments are TimeADT, but we leave them as generic Datums |
| 542 | + * to avoid dereferencing nulls (TimeADT is pass-by-reference!) |
| 543 | + */ |
| 544 | +Datumts1=PG_GETARG_DATUM(0); |
| 545 | +Datumte1=PG_GETARG_DATUM(1); |
| 546 | +Datumts2=PG_GETARG_DATUM(2); |
| 547 | +Datumte2=PG_GETARG_DATUM(3); |
| 548 | +boolts1IsNull=PG_ARGISNULL(0); |
| 549 | +boolte1IsNull=PG_ARGISNULL(1); |
| 550 | +boolts2IsNull=PG_ARGISNULL(2); |
| 551 | +boolte2IsNull=PG_ARGISNULL(3); |
543 | 552 |
|
544 | | -/* Make sure we have ordered pairs... */ |
545 | | -if (ts1>te1) |
546 | | -{ |
547 | | -TimeADTtt=ts1; |
| 553 | +#defineTIMEADT_GT(t1,t2) \ |
| 554 | +(DatumGetTimeADT(t1) >DatumGetTimeADT(t2)) |
| 555 | +#defineTIMEADT_LT(t1,t2) \ |
| 556 | +(DatumGetTimeADT(t1) < DatumGetTimeADT(t2)) |
548 | 557 |
|
| 558 | +/* |
| 559 | + * If both endpoints of interval 1 are null, the result is null (unknown). |
| 560 | + * If just one endpoint is null, take ts1 as the non-null one. |
| 561 | + * Otherwise, take ts1 as the lesser endpoint. |
| 562 | + */ |
| 563 | +if (ts1IsNull) |
| 564 | +{ |
| 565 | +if (te1IsNull) |
| 566 | +PG_RETURN_NULL(); |
| 567 | +/* swap null for non-null */ |
549 | 568 | ts1=te1; |
550 | | -te1=tt; |
| 569 | +te1IsNull=true; |
551 | 570 | } |
552 | | -if (ts2>te2) |
| 571 | +elseif (!te1IsNull) |
553 | 572 | { |
554 | | -TimeADTtt=ts2; |
| 573 | +if (TIMEADT_GT(ts1,te1)) |
| 574 | +{ |
| 575 | +Datumtt=ts1; |
| 576 | + |
| 577 | +ts1=te1; |
| 578 | +te1=tt; |
| 579 | +} |
| 580 | +} |
555 | 581 |
|
| 582 | +/* Likewise for interval 2. */ |
| 583 | +if (ts2IsNull) |
| 584 | +{ |
| 585 | +if (te2IsNull) |
| 586 | +PG_RETURN_NULL(); |
| 587 | +/* swap null for non-null */ |
556 | 588 | ts2=te2; |
557 | | -te2=tt; |
| 589 | +te2IsNull= true; |
| 590 | +} |
| 591 | +elseif (!te2IsNull) |
| 592 | +{ |
| 593 | +if (TIMEADT_GT(ts2,te2)) |
| 594 | +{ |
| 595 | +Datumtt=ts2; |
| 596 | + |
| 597 | +ts2=te2; |
| 598 | +te2=tt; |
| 599 | +} |
558 | 600 | } |
559 | 601 |
|
560 | | -PG_RETURN_BOOL((ts1>ts2&& (ts1<te2||te1<te2))|| |
561 | | - (ts1<ts2&& (ts2<te1||te2<te1))|| |
562 | | - (ts1==ts2)); |
| 602 | +/* |
| 603 | + * At this point neither ts1 nor ts2 is null, so we can consider three |
| 604 | + * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2 |
| 605 | + */ |
| 606 | +if (TIMEADT_GT(ts1,ts2)) |
| 607 | +{ |
| 608 | +/* This case is ts1 < te2 OR te1 < te2, which may look redundant |
| 609 | + * but in the presence of nulls it's not quite completely so. |
| 610 | + */ |
| 611 | +if (te2IsNull) |
| 612 | +PG_RETURN_NULL(); |
| 613 | +if (TIMEADT_LT(ts1,te2)) |
| 614 | +PG_RETURN_BOOL(true); |
| 615 | +if (te1IsNull) |
| 616 | +PG_RETURN_NULL(); |
| 617 | +/* If te1 is not null then we had ts1 <= te1 above, and we just |
| 618 | + * found ts1 >= te2, hence te1 >= te2. |
| 619 | + */ |
| 620 | +PG_RETURN_BOOL(false); |
| 621 | +} |
| 622 | +elseif (TIMEADT_LT(ts1,ts2)) |
| 623 | +{ |
| 624 | +/* This case is ts2 < te1 OR te2 < te1 */ |
| 625 | +if (te1IsNull) |
| 626 | +PG_RETURN_NULL(); |
| 627 | +if (TIMEADT_LT(ts2,te1)) |
| 628 | +PG_RETURN_BOOL(true); |
| 629 | +if (te2IsNull) |
| 630 | +PG_RETURN_NULL(); |
| 631 | +/* If te2 is not null then we had ts2 <= te2 above, and we just |
| 632 | + * found ts2 >= te1, hence te2 >= te1. |
| 633 | + */ |
| 634 | +PG_RETURN_BOOL(false); |
| 635 | +} |
| 636 | +else |
| 637 | +{ |
| 638 | +/* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a |
| 639 | + * rather silly way of saying "true if both are nonnull, else null". |
| 640 | + */ |
| 641 | +if (te1IsNull||te2IsNull) |
| 642 | +PG_RETURN_NULL(); |
| 643 | +PG_RETURN_BOOL(true); |
| 644 | +} |
| 645 | + |
| 646 | +#undef TIMEADT_GT |
| 647 | +#undef TIMEADT_LT |
563 | 648 | } |
564 | 649 |
|
565 | 650 | /* timestamp_time() |
@@ -964,53 +1049,122 @@ timetz_mi_interval(PG_FUNCTION_ARGS) |
964 | 1049 | PG_RETURN_TIMETZADT_P(result); |
965 | 1050 | } |
966 | 1051 |
|
967 | | -/* overlaps_timetz() |
968 | | - * Implements the SQL92 OVERLAPS operator. |
969 | | - * Algorithm from Date and Darwen, 1997 |
| 1052 | +/* overlaps_timetz() --- implements the SQL92 OVERLAPS operator. |
| 1053 | + * |
| 1054 | + * Algorithm is per SQL92 spec. This is much harder than you'd think |
| 1055 | + * because the spec requires us to deliver a non-null answer in some cases |
| 1056 | + * where some of the inputs are null. |
970 | 1057 | */ |
971 | 1058 | Datum |
972 | 1059 | overlaps_timetz(PG_FUNCTION_ARGS) |
973 | 1060 | { |
974 | 1061 | /* The arguments are TimeTzADT *, but we leave them as generic Datums |
975 | | - * for convenience of notation. |
| 1062 | + * for convenience of notation --- and to avoid dereferencing nulls. |
976 | 1063 | */ |
977 | 1064 | Datumts1=PG_GETARG_DATUM(0); |
978 | 1065 | Datumte1=PG_GETARG_DATUM(1); |
979 | 1066 | Datumts2=PG_GETARG_DATUM(2); |
980 | 1067 | Datumte2=PG_GETARG_DATUM(3); |
| 1068 | +boolts1IsNull=PG_ARGISNULL(0); |
| 1069 | +boolte1IsNull=PG_ARGISNULL(1); |
| 1070 | +boolts2IsNull=PG_ARGISNULL(2); |
| 1071 | +boolte2IsNull=PG_ARGISNULL(3); |
981 | 1072 |
|
982 | 1073 | #defineTIMETZ_GT(t1,t2) \ |
983 | 1074 | DatumGetBool(DirectFunctionCall2(timetz_gt,t1,t2)) |
984 | 1075 | #defineTIMETZ_LT(t1,t2) \ |
985 | 1076 | DatumGetBool(DirectFunctionCall2(timetz_lt,t1,t2)) |
986 | | -#defineTIMETZ_EQ(t1,t2) \ |
987 | | -DatumGetBool(DirectFunctionCall2(timetz_eq,t1,t2)) |
988 | 1077 |
|
989 | | -/* Make sure we have ordered pairs... */ |
990 | | -if (TIMETZ_GT(ts1,te1)) |
| 1078 | +/* |
| 1079 | + * If both endpoints of interval 1 are null, the result is null (unknown). |
| 1080 | + * If just one endpoint is null, take ts1 as the non-null one. |
| 1081 | + * Otherwise, take ts1 as the lesser endpoint. |
| 1082 | + */ |
| 1083 | +if (ts1IsNull) |
991 | 1084 | { |
992 | | -Datumtt=ts1; |
993 | | - |
| 1085 | +if (te1IsNull) |
| 1086 | +PG_RETURN_NULL(); |
| 1087 | +/* swap null for non-null */ |
994 | 1088 | ts1=te1; |
995 | | -te1=tt; |
| 1089 | +te1IsNull=true; |
996 | 1090 | } |
997 | | -if (TIMETZ_GT(ts2,te2)) |
| 1091 | +elseif (!te1IsNull) |
998 | 1092 | { |
999 | | -Datumtt=ts2; |
| 1093 | +if (TIMETZ_GT(ts1,te1)) |
| 1094 | +{ |
| 1095 | +Datumtt=ts1; |
| 1096 | + |
| 1097 | +ts1=te1; |
| 1098 | +te1=tt; |
| 1099 | +} |
| 1100 | +} |
1000 | 1101 |
|
| 1102 | +/* Likewise for interval 2. */ |
| 1103 | +if (ts2IsNull) |
| 1104 | +{ |
| 1105 | +if (te2IsNull) |
| 1106 | +PG_RETURN_NULL(); |
| 1107 | +/* swap null for non-null */ |
1001 | 1108 | ts2=te2; |
1002 | | -te2=tt; |
| 1109 | +te2IsNull= true; |
| 1110 | +} |
| 1111 | +elseif (!te2IsNull) |
| 1112 | +{ |
| 1113 | +if (TIMETZ_GT(ts2,te2)) |
| 1114 | +{ |
| 1115 | +Datumtt=ts2; |
| 1116 | + |
| 1117 | +ts2=te2; |
| 1118 | +te2=tt; |
| 1119 | +} |
1003 | 1120 | } |
1004 | 1121 |
|
1005 | | -PG_RETURN_BOOL((TIMETZ_GT(ts1,ts2)&& |
1006 | | -(TIMETZ_LT(ts1,te2)||TIMETZ_LT(te1,te2)))|| |
1007 | | - (TIMETZ_GT(ts2,ts1)&& |
1008 | | -(TIMETZ_LT(ts2,te1)||TIMETZ_LT(te2,te1)))|| |
1009 | | -TIMETZ_EQ(ts1,ts2)); |
| 1122 | +/* |
| 1123 | + * At this point neither ts1 nor ts2 is null, so we can consider three |
| 1124 | + * cases: ts1 > ts2, ts1 < ts2, ts1 = ts2 |
| 1125 | + */ |
| 1126 | +if (TIMETZ_GT(ts1,ts2)) |
| 1127 | +{ |
| 1128 | +/* This case is ts1 < te2 OR te1 < te2, which may look redundant |
| 1129 | + * but in the presence of nulls it's not quite completely so. |
| 1130 | + */ |
| 1131 | +if (te2IsNull) |
| 1132 | +PG_RETURN_NULL(); |
| 1133 | +if (TIMETZ_LT(ts1,te2)) |
| 1134 | +PG_RETURN_BOOL(true); |
| 1135 | +if (te1IsNull) |
| 1136 | +PG_RETURN_NULL(); |
| 1137 | +/* If te1 is not null then we had ts1 <= te1 above, and we just |
| 1138 | + * found ts1 >= te2, hence te1 >= te2. |
| 1139 | + */ |
| 1140 | +PG_RETURN_BOOL(false); |
| 1141 | +} |
| 1142 | +elseif (TIMETZ_LT(ts1,ts2)) |
| 1143 | +{ |
| 1144 | +/* This case is ts2 < te1 OR te2 < te1 */ |
| 1145 | +if (te1IsNull) |
| 1146 | +PG_RETURN_NULL(); |
| 1147 | +if (TIMETZ_LT(ts2,te1)) |
| 1148 | +PG_RETURN_BOOL(true); |
| 1149 | +if (te2IsNull) |
| 1150 | +PG_RETURN_NULL(); |
| 1151 | +/* If te2 is not null then we had ts2 <= te2 above, and we just |
| 1152 | + * found ts2 >= te1, hence te2 >= te1. |
| 1153 | + */ |
| 1154 | +PG_RETURN_BOOL(false); |
| 1155 | +} |
| 1156 | +else |
| 1157 | +{ |
| 1158 | +/* For ts1 = ts2 the spec says te1 <> te2 OR te1 = te2, which is a |
| 1159 | + * rather silly way of saying "true if both are nonnull, else null". |
| 1160 | + */ |
| 1161 | +if (te1IsNull||te2IsNull) |
| 1162 | +PG_RETURN_NULL(); |
| 1163 | +PG_RETURN_BOOL(true); |
| 1164 | +} |
1010 | 1165 |
|
1011 | 1166 | #undef TIMETZ_GT |
1012 | 1167 | #undef TIMETZ_LT |
1013 | | -#undef TIMETZ_EQ |
1014 | 1168 | } |
1015 | 1169 |
|
1016 | 1170 | /* timestamp_timetz() |
|