|
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()
|
|