00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <stdio.h>
00017 #include "postgres.h"
00018 #include "executor/spi.h"
00019 #include "veil_funcs.h"
00020 #include "veil_version.h"
00021
00022
00023
00024
00025
00026 typedef bool (Fetch_fn)(HeapTuple, TupleDesc, void *);
00027
00028
00029
00030
00031
00032
00033 #define FETCH_SIZE 20
00034
00035
00036
00037
00038
00039
00040 static int4 query_depth = 0;
00041
00042
00043
00044
00045
00046 static TransactionId connection_xid = 0;
00047
00048
00049
00050
00051
00052
00053
00054
00055 extern int
00056 vl_spi_connect()
00057 {
00058 TransactionId xid = GetCurrentTransactionId();
00059
00060 if (query_depth > 0) {
00061 if (xid == connection_xid) {
00062
00063 SPI_push();
00064 }
00065 else {
00066
00067
00068
00069 query_depth = 0;
00070 }
00071 }
00072
00073 connection_xid = xid;
00074
00075 return SPI_connect();
00076 }
00077
00078
00079
00080
00081 extern int
00082 vl_spi_finish()
00083 {
00084 int spi_result = SPI_finish();
00085
00086 if (query_depth > 0) {
00087 SPI_pop();
00088
00089 }
00090
00091 return spi_result;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108 static void
00109 prepare_query(const char *qry,
00110 int nargs,
00111 Oid *argtypes,
00112 Datum *args,
00113 bool read_only,
00114 void **saved_plan)
00115 {
00116 void *plan;
00117 int prep_ok;
00118 int exec_result;
00119
00120 if (saved_plan && *saved_plan) {
00121
00122 plan = *saved_plan;
00123 }
00124 else {
00125 if (!(plan = SPI_prepare(qry, nargs, argtypes))) {
00126 ereport(ERROR,
00127 (errcode(ERRCODE_INTERNAL_ERROR),
00128 errmsg("prepare_query fails"),
00129 errdetail("SPI_prepare('%s') returns NULL "
00130 "(SPI_result = %d)",
00131 qry, SPI_result)));
00132 }
00133
00134 if (saved_plan) {
00135
00136 *saved_plan = SPI_saveplan(plan);
00137 }
00138 }
00139
00140 exec_result = SPI_execute_plan(plan, args, NULL, read_only, 0);
00141 if (exec_result < 0) {
00142 ereport(ERROR,
00143 (errcode(ERRCODE_INTERNAL_ERROR),
00144 errmsg("prepare_query fails"),
00145 errdetail("SPI_execute_plan('%s') returns error %d",
00146 qry, exec_result)));
00147 }
00148 }
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174 static int
00175 query(const char *qry,
00176 int nargs,
00177 Oid *argtypes,
00178 Datum *args,
00179 bool read_only,
00180 void **saved_plan,
00181 Fetch_fn process_row,
00182 void *fn_param)
00183 {
00184 int row;
00185 int fetched = 0;
00186 int exec_result;
00187
00188 query_depth++;
00189
00190 prepare_query(qry, nargs, argtypes, args, read_only, saved_plan);
00191
00192 for(row = 0; row < SPI_processed; row++) {
00193 fetched++;
00194
00195 if (!process_row(SPI_tuptable->vals[row],
00196 SPI_tuptable->tupdesc,
00197 fn_param))
00198 {
00199 break;
00200 }
00201 }
00202
00203 query_depth--;
00204 return fetched;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 static bool
00218 fetch_one_int(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
00219 {
00220 int4 col = DatumGetInt32(SPI_getbinval(tuple, tupdesc, 1, false));
00221 *((int4 *) p_result) = col;
00222
00223 return false;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236 static bool
00237 fetch_one_bool(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
00238 {
00239 bool col = DatumGetBool(SPI_getbinval(tuple, tupdesc, 1, false));
00240 *((bool *) p_result) = col;
00241
00242 return false;
00243 }
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 static bool
00256 fetch_one_str(HeapTuple tuple, TupleDesc tupdesc, void *p_result)
00257 {
00258 char *col = SPI_getvalue(tuple, tupdesc, 1);
00259 char **p_str = (char **) p_result;
00260 *p_str = col;
00261
00262 return false;
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273 static bool
00274 int_from_query(const char *qry,
00275 int4 *result)
00276 {
00277 int rows;
00278 Oid argtypes[0];
00279 Datum args[0];
00280 rows = query(qry, 0, argtypes, args, false, NULL,
00281 fetch_one_int, (void *)result);
00282 return (rows > 0);
00283 }
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293 bool
00294 vl_bool_from_query(const char *qry,
00295 bool *result)
00296 {
00297 int rows;
00298 Oid argtypes[0];
00299 Datum args[0];
00300 rows = query(qry, 0, argtypes, args, false, NULL,
00301 fetch_one_bool, (void *)result);
00302 return (rows > 0);
00303 }
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314 static bool
00315 str_from_oid_query(const char *qry,
00316 const Oid param,
00317 char *result)
00318 {
00319 int rows;
00320 Oid argtypes[1] = {OIDOID};
00321 Datum args[1];
00322
00323 args[0] = ObjectIdGetDatum(param);
00324 rows = query(qry, 1, argtypes, args, false, NULL,
00325 fetch_one_str, (void *)result);
00326 return (rows > 0);
00327 }
00328
00329
00330
00331
00332
00333
00334
00335
00336 static void
00337 check_type(Oid oid,
00338 Oid expected_oid,
00339 const char *msg)
00340 {
00341 if (oid != expected_oid) {
00342 char *expected;
00343 char *actual;
00344 bool ok;
00345 if (str_from_oid_query("select typname from pg_type where oid = $1",
00346 expected_oid, (void *) &expected) &&
00347 str_from_oid_query("select typname from pg_type where oid = $1",
00348 oid, (void *) &actual))
00349 {
00350 ereport(ERROR,
00351 (errcode(ERRCODE_INTERNAL_ERROR),
00352 errmsg("Type mismatch"),
00353 errdetail("Expected %s, got %s): %s",
00354 expected, actual, msg)));
00355 }
00356 else {
00357
00358 ereport(ERROR,
00359 (errcode(ERRCODE_INTERNAL_ERROR),
00360 errmsg("Type mismatch"),
00361 errdetail("Incorrect type: %s", msg)));
00362 }
00363 }
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374 extern bool
00375 vl_db_exists(Oid db_id)
00376 {
00377 char dbname[NAMEDATALEN + 1];
00378
00379 return str_from_oid_query("select datname from pg_database where oid = $1",
00380 db_id, dbname);
00381 }
00382
00383