00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "postgres.h"
00015
00016 #include "utils/builtins.h"
00017 #include "windowapi.h"
00018
00019
00020
00021
00022 typedef struct rank_context
00023 {
00024 int64 rank;
00025 } rank_context;
00026
00027
00028
00029
00030 typedef struct
00031 {
00032 int32 ntile;
00033 int64 rows_per_bucket;
00034 int64 boundary;
00035 int64 remainder;
00036 } ntile_context;
00037
00038 static bool rank_up(WindowObject winobj);
00039 static Datum leadlag_common(FunctionCallInfo fcinfo,
00040 bool forward, bool withoffset, bool withdefault);
00041
00042
00043
00044
00045
00046 static bool
00047 rank_up(WindowObject winobj)
00048 {
00049 bool up = false;
00050 int64 curpos = WinGetCurrentPosition(winobj);
00051 rank_context *context;
00052
00053 context = (rank_context *)
00054 WinGetPartitionLocalMemory(winobj, sizeof(rank_context));
00055
00056 if (context->rank == 0)
00057 {
00058
00059 Assert(curpos == 0);
00060 context->rank = 1;
00061 }
00062 else
00063 {
00064 Assert(curpos > 0);
00065
00066 if (!WinRowsArePeers(winobj, curpos - 1, curpos))
00067 up = true;
00068 }
00069
00070
00071 WinSetMarkPosition(winobj, curpos);
00072
00073 return up;
00074 }
00075
00076
00077
00078
00079
00080
00081 Datum
00082 window_row_number(PG_FUNCTION_ARGS)
00083 {
00084 WindowObject winobj = PG_WINDOW_OBJECT();
00085 int64 curpos = WinGetCurrentPosition(winobj);
00086
00087 WinSetMarkPosition(winobj, curpos);
00088 PG_RETURN_INT64(curpos + 1);
00089 }
00090
00091
00092
00093
00094
00095
00096
00097 Datum
00098 window_rank(PG_FUNCTION_ARGS)
00099 {
00100 WindowObject winobj = PG_WINDOW_OBJECT();
00101 rank_context *context;
00102 bool up;
00103
00104 up = rank_up(winobj);
00105 context = (rank_context *)
00106 WinGetPartitionLocalMemory(winobj, sizeof(rank_context));
00107 if (up)
00108 context->rank = WinGetCurrentPosition(winobj) + 1;
00109
00110 PG_RETURN_INT64(context->rank);
00111 }
00112
00113
00114
00115
00116
00117 Datum
00118 window_dense_rank(PG_FUNCTION_ARGS)
00119 {
00120 WindowObject winobj = PG_WINDOW_OBJECT();
00121 rank_context *context;
00122 bool up;
00123
00124 up = rank_up(winobj);
00125 context = (rank_context *)
00126 WinGetPartitionLocalMemory(winobj, sizeof(rank_context));
00127 if (up)
00128 context->rank++;
00129
00130 PG_RETURN_INT64(context->rank);
00131 }
00132
00133
00134
00135
00136
00137
00138
00139 Datum
00140 window_percent_rank(PG_FUNCTION_ARGS)
00141 {
00142 WindowObject winobj = PG_WINDOW_OBJECT();
00143 rank_context *context;
00144 bool up;
00145 int64 totalrows = WinGetPartitionRowCount(winobj);
00146
00147 Assert(totalrows > 0);
00148
00149 up = rank_up(winobj);
00150 context = (rank_context *)
00151 WinGetPartitionLocalMemory(winobj, sizeof(rank_context));
00152 if (up)
00153 context->rank = WinGetCurrentPosition(winobj) + 1;
00154
00155
00156 if (totalrows <= 1)
00157 PG_RETURN_FLOAT8(0.0);
00158
00159 PG_RETURN_FLOAT8((float8) (context->rank - 1) / (float8) (totalrows - 1));
00160 }
00161
00162
00163
00164
00165
00166
00167
00168 Datum
00169 window_cume_dist(PG_FUNCTION_ARGS)
00170 {
00171 WindowObject winobj = PG_WINDOW_OBJECT();
00172 rank_context *context;
00173 bool up;
00174 int64 totalrows = WinGetPartitionRowCount(winobj);
00175
00176 Assert(totalrows > 0);
00177
00178 up = rank_up(winobj);
00179 context = (rank_context *)
00180 WinGetPartitionLocalMemory(winobj, sizeof(rank_context));
00181 if (up || context->rank == 1)
00182 {
00183
00184
00185
00186
00187 int64 row;
00188
00189 context->rank = WinGetCurrentPosition(winobj) + 1;
00190
00191
00192
00193
00194 for (row = context->rank; row < totalrows; row++)
00195 {
00196 if (!WinRowsArePeers(winobj, row - 1, row))
00197 break;
00198 context->rank++;
00199 }
00200 }
00201
00202 PG_RETURN_FLOAT8((float8) context->rank / (float8) totalrows);
00203 }
00204
00205
00206
00207
00208
00209
00210 Datum
00211 window_ntile(PG_FUNCTION_ARGS)
00212 {
00213 WindowObject winobj = PG_WINDOW_OBJECT();
00214 ntile_context *context;
00215
00216 context = (ntile_context *)
00217 WinGetPartitionLocalMemory(winobj, sizeof(ntile_context));
00218
00219 if (context->ntile == 0)
00220 {
00221
00222 int64 total;
00223 int32 nbuckets;
00224 bool isnull;
00225
00226 total = WinGetPartitionRowCount(winobj);
00227 nbuckets = DatumGetInt32(WinGetFuncArgCurrent(winobj, 0, &isnull));
00228
00229
00230
00231
00232
00233 if (isnull)
00234 PG_RETURN_NULL();
00235
00236
00237
00238
00239
00240 if (nbuckets <= 0)
00241 ereport(ERROR,
00242 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_NTILE),
00243 errmsg("argument of ntile must be greater than zero")));
00244
00245 context->ntile = 1;
00246 context->rows_per_bucket = 0;
00247 context->boundary = total / nbuckets;
00248 if (context->boundary <= 0)
00249 context->boundary = 1;
00250 else
00251 {
00252
00253
00254
00255
00256 context->remainder = total % nbuckets;
00257 if (context->remainder != 0)
00258 context->boundary++;
00259 }
00260 }
00261
00262 context->rows_per_bucket++;
00263 if (context->boundary < context->rows_per_bucket)
00264 {
00265
00266 if (context->remainder != 0 && context->ntile == context->remainder)
00267 {
00268 context->remainder = 0;
00269 context->boundary -= 1;
00270 }
00271 context->ntile += 1;
00272 context->rows_per_bucket = 1;
00273 }
00274
00275 PG_RETURN_INT32(context->ntile);
00276 }
00277
00278
00279
00280
00281
00282
00283
00284
00285 static Datum
00286 leadlag_common(FunctionCallInfo fcinfo,
00287 bool forward, bool withoffset, bool withdefault)
00288 {
00289 WindowObject winobj = PG_WINDOW_OBJECT();
00290 int32 offset;
00291 bool const_offset;
00292 Datum result;
00293 bool isnull;
00294 bool isout;
00295
00296 if (withoffset)
00297 {
00298 offset = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
00299 if (isnull)
00300 PG_RETURN_NULL();
00301 const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
00302 }
00303 else
00304 {
00305 offset = 1;
00306 const_offset = true;
00307 }
00308
00309 result = WinGetFuncArgInPartition(winobj, 0,
00310 (forward ? offset : -offset),
00311 WINDOW_SEEK_CURRENT,
00312 const_offset,
00313 &isnull, &isout);
00314
00315 if (isout)
00316 {
00317
00318
00319
00320
00321 if (withdefault)
00322 result = WinGetFuncArgCurrent(winobj, 2, &isnull);
00323 }
00324
00325 if (isnull)
00326 PG_RETURN_NULL();
00327
00328 PG_RETURN_DATUM(result);
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 Datum
00338 window_lag(PG_FUNCTION_ARGS)
00339 {
00340 return leadlag_common(fcinfo, false, false, false);
00341 }
00342
00343
00344
00345
00346
00347
00348
00349 Datum
00350 window_lag_with_offset(PG_FUNCTION_ARGS)
00351 {
00352 return leadlag_common(fcinfo, false, true, false);
00353 }
00354
00355
00356
00357
00358
00359
00360 Datum
00361 window_lag_with_offset_and_default(PG_FUNCTION_ARGS)
00362 {
00363 return leadlag_common(fcinfo, false, true, true);
00364 }
00365
00366
00367
00368
00369
00370
00371
00372 Datum
00373 window_lead(PG_FUNCTION_ARGS)
00374 {
00375 return leadlag_common(fcinfo, true, false, false);
00376 }
00377
00378
00379
00380
00381
00382
00383
00384 Datum
00385 window_lead_with_offset(PG_FUNCTION_ARGS)
00386 {
00387 return leadlag_common(fcinfo, true, true, false);
00388 }
00389
00390
00391
00392
00393
00394
00395 Datum
00396 window_lead_with_offset_and_default(PG_FUNCTION_ARGS)
00397 {
00398 return leadlag_common(fcinfo, true, true, true);
00399 }
00400
00401
00402
00403
00404
00405
00406 Datum
00407 window_first_value(PG_FUNCTION_ARGS)
00408 {
00409 WindowObject winobj = PG_WINDOW_OBJECT();
00410 Datum result;
00411 bool isnull;
00412
00413 result = WinGetFuncArgInFrame(winobj, 0,
00414 0, WINDOW_SEEK_HEAD, true,
00415 &isnull, NULL);
00416 if (isnull)
00417 PG_RETURN_NULL();
00418
00419 PG_RETURN_DATUM(result);
00420 }
00421
00422
00423
00424
00425
00426
00427 Datum
00428 window_last_value(PG_FUNCTION_ARGS)
00429 {
00430 WindowObject winobj = PG_WINDOW_OBJECT();
00431 Datum result;
00432 bool isnull;
00433
00434 result = WinGetFuncArgInFrame(winobj, 0,
00435 0, WINDOW_SEEK_TAIL, true,
00436 &isnull, NULL);
00437 if (isnull)
00438 PG_RETURN_NULL();
00439
00440 PG_RETURN_DATUM(result);
00441 }
00442
00443
00444
00445
00446
00447
00448 Datum
00449 window_nth_value(PG_FUNCTION_ARGS)
00450 {
00451 WindowObject winobj = PG_WINDOW_OBJECT();
00452 bool const_offset;
00453 Datum result;
00454 bool isnull;
00455 int32 nth;
00456
00457 nth = DatumGetInt32(WinGetFuncArgCurrent(winobj, 1, &isnull));
00458 if (isnull)
00459 PG_RETURN_NULL();
00460 const_offset = get_fn_expr_arg_stable(fcinfo->flinfo, 1);
00461
00462 if (nth <= 0)
00463 ereport(ERROR,
00464 (errcode(ERRCODE_INVALID_ARGUMENT_FOR_NTH_VALUE),
00465 errmsg("argument of nth_value must be greater than zero")));
00466
00467 result = WinGetFuncArgInFrame(winobj, 0,
00468 nth - 1, WINDOW_SEEK_HEAD, const_offset,
00469 &isnull, NULL);
00470 if (isnull)
00471 PG_RETURN_NULL();
00472
00473 PG_RETURN_DATUM(result);
00474 }