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