1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2011 Stewart Smith
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23
#include <drizzled/module/module.h>
24
#include <drizzled/module/context.h>
25
#include <drizzled/plugin/plugin.h>
26
#include <drizzled/plugin.h>
27
#include <drizzled/sys_var.h>
28
#include <drizzled/gettext.h>
29
#include <drizzled/error.h>
30
#include <drizzled/query_id.h>
31
#include <drizzled/session.h>
32
#include <drizzled/internal/my_sys.h>
33
#include <drizzled/internal/m_string.h>
36
#include <boost/program_options.hpp>
37
#include <drizzled/module/option_map.h>
38
#include <drizzled/constrained_value.h>
42
#include <drizzled/execute.h>
43
#include <drizzled/sql/result_set.h>
45
#include <drizzled/plugin/listen.h>
46
#include <drizzled/plugin/client.h>
47
#include <drizzled/catalog/local.h>
49
#include <drizzled/version.h>
50
#include <plugin/json_server/json/json.h>
52
namespace po= boost::program_options;
53
using namespace drizzled;
56
namespace drizzle_plugin
61
static port_constraint port;
62
struct event_base *base= NULL;
65
static in_port_t getPort(void)
70
extern "C" void process_request(struct evhttp_request *req, void* );
71
extern "C" void process_root_request(struct evhttp_request *req, void* );
72
extern "C" void process_api01_version_req(struct evhttp_request *req, void* );
73
extern "C" void process_api01_sql_req(struct evhttp_request *req, void* );
75
extern "C" void process_request(struct evhttp_request *req, void* )
77
struct evbuffer *buf = evbuffer_new();
78
if (buf == NULL) return;
79
evbuffer_add_printf(buf, "Requested: %s\n", evhttp_request_uri(req));
80
evhttp_send_reply(req, HTTP_OK, "OK", buf);
83
extern "C" void process_root_request(struct evhttp_request *req, void* )
85
struct evbuffer *buf = evbuffer_new();
86
if (buf == NULL) return;
90
output.append("<html><head><title>JSON DATABASE interface demo</title></head>"
92
"<script lang=\"javascript\">"
93
"function to_table(obj) {"
94
" var str = '<table>';"
95
"for (var r=0; r< obj.length; r++) {"
97
" for (var c=0; c < obj[r].length; c++) {"
98
" str+= '<td>' + obj[r][c] + '</td>';"
105
"function run_query()\n"
107
"var url = document.getElementById(\"baseurl\").innerHTML;\n"
108
"var query= document.getElementById(\"query\").value;\n"
109
"var xmlHttp = new XMLHttpRequest();\n"
110
"xmlHttp.onreadystatechange = function () {\n"
111
"if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {\n"
112
"var info = eval ( \"(\" + xmlHttp.responseText + \")\" );\n"
113
"document.getElementById( \"resultset\").innerHTML= to_table(info.result_set);\n"
116
"xmlHttp.open(\"POST\", url + \"/0.1/sql\", true);"
117
"xmlHttp.send(query);"
120
"function update_version()\n"
121
"{drizzle_version(document.getElementById(\"baseurl\").innerHTML);}\n\n"
122
"function drizzle_version($url)"
124
"var xmlHttp = new XMLHttpRequest();\n"
125
"xmlHttp.onreadystatechange = function () {\n"
126
"if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {\n"
127
"var info = eval ( \"(\" + xmlHttp.responseText + \")\" );\n"
128
"document.getElementById( \"drizzleversion\").innerHTML= info.version;\n"
131
"xmlHttp.open(\"GET\", $url + \"/0.1/version\", true);"
132
"xmlHttp.send(null);"
135
"<p>Drizzle Server at: <a id=\"baseurl\">http://localhost:8765</a></p>"
136
"<p>Drizzle server version: <a id=\"drizzleversion\"></a></p>"
137
"<p><textarea rows=\"3\" cols=\"40\" id=\"query\">"
138
"SELECT * from DATA_DICTIONARY.GLOBAL_STATUS;"
140
"<button type=\"button\" onclick=\"run_query();\">Execute Query</button>"
141
"<div id=\"resultset\"/>"
142
"<script lang=\"javascript\">update_version(); run_query();</script>"
145
evbuffer_add(buf, output.c_str(), output.length());
146
evhttp_send_reply(req, HTTP_OK, "OK", buf);
149
extern "C" void process_api01_version_req(struct evhttp_request *req, void* )
151
struct evbuffer *buf = evbuffer_new();
152
if (buf == NULL) return;
155
root["version"]= ::drizzled::version();
157
Json::StyledWriter writer;
158
std::string output= writer.write(root);
160
evbuffer_add(buf, output.c_str(), output.length());
161
evhttp_send_reply(req, HTTP_OK, "OK", buf);
164
extern "C" void process_api01_sql_req(struct evhttp_request *req, void* )
166
struct evbuffer *buf = evbuffer_new();
167
if (buf == NULL) return;
173
l= evbuffer_remove(req->input_buffer, buffer, 1024);
174
input.append(buffer, l);
177
drizzled::Session::shared_ptr _session= drizzled::Session::make_shared(drizzled::plugin::Listen::getNullClient(),
178
drizzled::catalog::local());
179
drizzled::identifier::user::mptr user_id= identifier::User::make_shared();
180
user_id->setUser("");
181
_session->setUser(user_id);
182
_session->set_db("test");
184
drizzled::Execute execute(*(_session.get()), true);
186
drizzled::sql::ResultSet result_set(1);
188
/* Execute wraps the SQL to run within a transaction */
189
execute.run(input, result_set);
190
drizzled::sql::Exception exception= result_set.getException();
192
drizzled::error_t err= exception.getErrorCode();
195
root["sqlstate"]= exception.getSQLState();
197
if ((err != drizzled::EE_OK) && (err != drizzled::ER_EMPTY_QUERY))
199
root["error_message"]= exception.getErrorMessage();
200
root["error_code"]= exception.getErrorCode();
203
while (result_set.next())
205
Json::Value json_row;
206
for (size_t x= 0; x < result_set.getMetaData().getColumnCount(); x++)
208
if (not result_set.isNull(x))
210
json_row[x]= result_set.getString(x);
213
root["result_set"].append(json_row);
216
root["query"]= input;
218
Json::StyledWriter writer;
219
std::string output= writer.write(root);
221
evbuffer_add(buf, output.c_str(), output.length());
222
evhttp_send_reply(req, HTTP_OK, "OK", buf);
225
extern "C" void *libevent_thread(void*);
227
extern "C" void *libevent_thread(void*)
229
internal::my_thread_init();
231
event_base_dispatch(base);
236
static int json_server_init(drizzled::module::Context &context)
238
context.registerVariable(new sys_var_constrained_value_readonly<in_port_t>("port", port));
241
httpd= evhttp_new(base);
245
int r= evhttp_bind_socket(httpd, "0.0.0.0", getPort());
250
evhttp_set_cb(httpd, "/", process_root_request, NULL);
251
evhttp_set_cb(httpd, "/0.1/version", process_api01_version_req, NULL);
252
evhttp_set_cb(httpd, "/0.1/sql", process_api01_sql_req, NULL);
253
evhttp_set_gencb(httpd, process_request, NULL);
255
pthread_t libevent_loop_thread;
257
pthread_create(&libevent_loop_thread, NULL, libevent_thread, NULL);
262
static void init_options(drizzled::module::option_context &context)
265
po::value<port_constraint>(&port)->default_value(80),
266
_("Port number to use for connection or 0 for default (port 80) "));
269
} /* namespace json_server */
270
} /* namespace drizzle_plugin */
272
DRIZZLE_DECLARE_PLUGIN
278
"JSON HTTP interface",
280
drizzle_plugin::json_server::json_server_init, /* Plugin Init */
282
drizzle_plugin::json_server::init_options /* config options */
284
DRIZZLE_DECLARE_PLUGIN_END;