root/platform/mysql/top-n-sort/top-n-sort.c

Revision 26579, 5.3 kB (checked in by kazuho, 5 years ago)

add negative order mode

Line 
1#include <mysql.h>
2#include <pthread.h>
3#include <stdlib.h>
4#include <string.h>
5
6#ifndef MAX_ITEMS
7# define MAX_ITEMS 200
8#endif
9
10extern void topn_init(void) __attribute__ ((constructor));
11extern void topn_fini(void) __attribute__ ((destructor));
12
13extern my_bool topn_set_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
14extern void topn_set_deinit(UDF_INIT *initid);
15extern void topn_set_reset(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
16                           char *error);
17extern void topn_set_clear(UDF_INIT *initid, char *is_null, char *error);
18extern void topn_set_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
19                          char *error);
20extern long long topn_set(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
21                          char *error);
22extern my_bool topn_get_init(UDF_INIT *initid, UDF_ARGS *args, char *message);
23extern void topn_get_deinit(UDF_INIT *initid);
24extern long long topn_get(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
25                          char *error);
26extern my_bool topn_get_value_init(UDF_INIT *initid, UDF_ARGS *args,
27                                   char *message);
28extern void topn_get_value_deinit(UDF_INIT *initid);
29extern long long topn_get_value(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
30                                char *error);
31
32typedef struct _topn_item {
33  long long id;
34  long long value;
35} topn_item;
36
37typedef struct _topn_info {
38  int refcnt;
39  int count;
40  topn_item items[MAX_ITEMS];
41} topn_info;
42
43static pthread_key_t pkey_;
44
45void topn_init(void)
46{
47  pthread_key_create(&pkey_, NULL);
48}
49
50void topn_fini(void)
51{
52  pthread_key_delete(pkey_);
53}
54
55__inline topn_info *get_info(void)
56{
57  return pthread_getspecific(pkey_);
58}
59
60static topn_info *acquire_info(void)
61{
62  topn_info *info;
63 
64  if ((info = get_info()) != NULL) {
65    info->refcnt++;
66    return info;
67  }
68 
69  if ((info = malloc(sizeof(*info))) == NULL) {
70    return NULL;
71  }
72 
73  info->refcnt = 1;
74  info->count = 0;
75  pthread_setspecific(pkey_, info);
76  return info;
77}
78
79static void release_info(topn_info *info)
80{
81  if (--info->refcnt == 0) {
82    free(info);
83    pthread_setspecific(pkey_, NULL);
84  }
85}
86
87#define SETUP_ARG(i, t, n)   \
88  do {                       \
89    args->arg_type[i] = t;   \
90    args->maybe_null[i] = n; \
91  } while (0)
92
93my_bool topn_set_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
94{
95  if (args->arg_count != 3) {
96    strcpy(message, "topn_set_init(max_items,id,value): invalid arguments");
97    return 1;
98  }
99  if ((initid->ptr = (char*)acquire_info()) == NULL) {
100    strcpy(message, "no memory");
101    return 1;
102  }
103 
104  initid->maybe_null = 0;
105  SETUP_ARG(0, INT_RESULT, 0);
106  SETUP_ARG(1, INT_RESULT, 0);
107  SETUP_ARG(2, INT_RESULT, 0);
108  return 0;
109}
110
111void topn_set_deinit(UDF_INIT *initid)
112{
113  release_info((topn_info*)initid->ptr);
114}
115
116void topn_set_reset(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
117                    char *error)
118{
119  topn_set_clear(initid, is_null, error);
120  topn_set_add(initid, args, is_null, error);
121}
122
123void topn_set_clear(UDF_INIT *initid, char *is_null, char *error)
124{
125  topn_info *info = (topn_info*)initid->ptr;
126  info->count = 0;
127}
128
129void topn_set_add(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
130{
131  topn_info *info = (topn_info*)initid->ptr;
132  int max_items = (int)*(long long*)args->args[0];
133  long long id = *(long long*)args->args[1],
134    value = *(long long*)args->args[2];
135  int keep, i;
136 
137  for (keep = info->count - 1; keep >= 0; keep--) {
138    if (info->items[keep].value < value
139        || (info->items[keep].value == value && info->items[keep].id < id)) {
140      break;
141    }
142  }
143  if (keep != max_items - 1) {
144    if (info->count < max_items) {
145      info->count++;
146    }
147    for (i = info->count - 2; i > keep; i--) {
148      memcpy(info->items + i + 1, info->items + i, sizeof(info->items[0]));
149    }
150    info->items[keep + 1].id = id;
151    info->items[keep + 1].value = value;
152  }
153}
154
155long long topn_set(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
156{
157  topn_info *info = (topn_info*)initid->ptr;
158  return info->count;
159}
160
161my_bool topn_get_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
162{
163  if (args->arg_count != 1) {
164    strcpy(message, "topn_get(index): invalid arguments");
165    return 1;
166  }
167  if ((initid->ptr = (char*)acquire_info()) == NULL) {
168    strcpy(message, "no memory");
169    return 1;
170  }
171 
172  initid->maybe_null = 0;
173  SETUP_ARG(0, INT_RESULT, 0);
174  return 0;
175}
176
177void topn_get_deinit(UDF_INIT *initid)
178{
179  release_info((topn_info*)initid->ptr);
180}
181
182long long topn_get(UDF_INIT *initid, UDF_ARGS *args, char *is_null, char *error)
183{
184  topn_info *info = (topn_info*)initid->ptr;
185  int idx = (int)*(long long*)args->args[0];
186 
187  if (idx < 0) {
188    idx += info->count;
189  }
190  return 0 <= idx && idx < info->count ? info->items[idx].id : 0;
191}
192
193my_bool topn_get_value_init(UDF_INIT *initid, UDF_ARGS *args, char *message)
194{
195  if (args->arg_count != 1) {
196    strcpy(message, "topn_get_value(index): invalid arguments");
197    return 1;
198  }
199  if ((initid->ptr = (char*)acquire_info()) == NULL) {
200    strcpy(message, "no memory");
201    return 1;
202  }
203 
204  initid->maybe_null = 0;
205  SETUP_ARG(0, INT_RESULT, 0);
206  return 0;
207}
208
209void topn_get_value_deinit(UDF_INIT *initid)
210{
211  release_info((topn_info*)initid->ptr);
212}
213
214long long topn_get_value(UDF_INIT *initid, UDF_ARGS *args, char *is_null,
215                         char *error)
216{
217  topn_info *info = (topn_info*)initid->ptr;
218  int idx = (int)*(long long*)args->args[0];
219 
220  if (idx < 0) {
221    idx += info->count;
222  }
223  return 0 <= idx && idx < info->count ? info->items[idx].value : 0;
224}
225
Note: See TracBrowser for help on using the browser.