Skip to content

Instantly share code, notes, and snippets.

@mrlannigan
Last active December 22, 2015 06:08
Show Gist options
  • Save mrlannigan/6428507 to your computer and use it in GitHub Desktop.
Save mrlannigan/6428507 to your computer and use it in GitHub Desktop.
Coldfusion Query Tool

Coldfusion Query Tool

This is a one-page "app" that will allow one to run queries against a configurable datasource.

WARNING

This is not a secure app in any way shape or form. The only form of protection it offers is a check for the cgi.REMOTE_ADDR to be 127.0.0.1. This app uses dangerous methods to run the query.

Requirements

The folder this script lives in must have write permissions to the folder.

<cfparam name="form.query" default="">
<cfparam name="form.ajax" default="">
<cfparam name="form.datasource" default="">
<cfif cgi.REMOTE_ADDR NEQ '127.0.0.1'>
<cfheader statuscode="401" statustext="Unauthorized"/>
<cfoutput>not authorized</cfoutput>
<cfabort />
</cfif>
<cfif form.ajax EQ true>
<cfset result = {}>
<cfset result['body'] = ''>
<cfset result['jsonbody'] = '{}'>
<cfsetting showdebugoutput="false">
<cfset queryFile = '<cfquery datasource="#form.datasource#" name="poop" maxrows="10">#deserializeJSON(form.query).query#</cfquery>'>
<cftry>
<cffile action="write" file="#GetDirectoryFromPath(getCurrentTemplatePath())#cfquery2013.cfm" output="#queryFile#">
<cfinclude template="cfquery2013.cfm">
<cffile action="delete" file="#GetDirectoryFromPath(getCurrentTemplatePath())#cfquery2013.cfm">
<cfsavecontent variable="bodypoop">
<cfoutput><cfdump var="#poop#" label="Result"></cfoutput>
</cfsavecontent>
<cfset result['jsonbody'] = []>
<cfloop query="poop">
<cfset tmp = {}>
<cfloop list="#poop.columnlist#" index="field">
<cfset tmp[field] = poop[field][poop.currentRow]>
</cfloop>
<cfset arrayAppend(result['jsonbody'], duplicate(tmp))>
</cfloop>
<cfset result['jsonbody'] = serializeJSON(result['jsonbody'])>
<cfcatch>
<cffile action="delete" file="#GetDirectoryFromPath(getCurrentTemplatePath())#cfquery2013.cfm">
<cfsavecontent variable="bodypoop">
<cfoutput><cfdump var="#cfcatch#" format="html"></cfoutput>
</cfsavecontent>
</cfcatch>
</cftry>
<cfset result['body'] = bodypoop>
<cfheader name="Content-Type" value="application/json">
<cfoutput>#serializeJSON(result)#</cfoutput>
<cfabort />
</cfif>
<cfoutput><!DOCTYPE html>
<html lang="en">
<head>
<title>CF Query</title>
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
<link rel="stylesheet" href="http://blog.yesmeck.com/jquery-jsonview/stylesheets/jquery.jsonview.css" type="text/css" media="screen" title="no title" charset="utf-8">
</head>
<body>
<div class="" style="margin: 0 15px">
<div class="row">
<div class="col-md-12 page-header"><h1>Query Oracle</h1></div>
</div>
<div class="row">
<div class="col-md-10"><textarea class="form-control query" rows="3"></textarea></div>
<div class="col-md-2">
<div class="btn-group">
<button type="button" class="btn btn-default" data-toggle="modal" data-target="##prevModal">History</button>
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
<span class="datasource">Dropdown</span>
<span class="caret"></span>
</button>
<ul class="dropdown-menu datasources">
</ul>
</div>
</div>
<br>
<div class="btn-group">
<button type="button" class="btn btn-primary do-query">Query</button>
<button type="button" class="btn btn-default add-datasource">Add Datasource</button>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12"><hr></div>
</div>
<div class="row">
<div class="col-md-12 query-result"></div>
</div>
<div class="row">
<div class="col-md-12"><hr></div>
</div>
<div class="row">
<div class="col-md-12 query-json-result"></div>
</div>
</div>
<div class="modal fade" id="prevModal" tabindex="-1" role="dialog" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="list-group prev-queries">
</div>
</div>
</div>
</div>
</div>
<script src="//code.jquery.com/jquery-1.10.1.min.js"></script>
<script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<script src="http://blog.yesmeck.com/jquery-jsonview/javascripts/jquery.jsonview.js" type="text/javascript"></script>
<script>
(function ($) {
var $modal = $('##prevModal'),
$prevQueries = $('.prev-queries'),
$query = $('textarea.query'),
$queryResult = $('.query-result'),
$queryJSONResult = $('.query-json-result'),
$datasource = $('.datasource');
function doQuery(callback) {
var query = $query.val();
saveToHistory(query);
$queryResult.html('<div class="alert alert-info">Loading...</div>');
$queryJSONResult.html('');
$.ajax({
method: 'post',
data: {
ajax: true,
query: JSON.stringify({query:query}),
datasource: $datasource.text()
}
}).done(function (data, textStatus, jqXHR) {
$queryResult.html(data.body);
$queryJSONResult.JSONView(data.jsonbody || {});
}).fail(function (jqXHR, textStatus, errorThrown) {
$queryResult.html('<div class="alert alert-danger"><strong>Error</strong> '+ errorThrown +'</div>');
});
}
function saveToHistory(query) {
var rerun = false,
latestQuery = $prevQueries.find('a').first();
if (query.length < 1) {
return false;
}
if (latestQuery.length && latestQuery.find('.query').text() == query) {
if (latestQuery.find('.badge').length) {
latestQuery.find('.badge').text(1 * latestQuery.find('.badge').text() + 1);
} else {
latestQuery.prepend('<span class="badge">2</span>');
}
} else {
$prevQueries.prepend('<a href="##" class="list-group-item prev-item"><span class="query"></span></a>');
$prevQueries.find('a').first().find('.query').text(query);
}
while ($prevQueries.length > 100) {
$prevQueries.last().remove();
}
localStorage['query.prevqueries'] = $prevQueries.html();
}
function loadHistory() {
if (!localStorage['query.prevqueries']) {
return false;
}
$prevQueries.html(localStorage['query.prevqueries']);
}
$(function () {
$(document).on('click', '.prev-item', function () {
$modal.modal('hide');
$query.val($(this).find('.query').text());
return false;
})
.on('click', '.btn.do-query', function (e) {
e.preventDefault();
doQuery(function () {
//something
});
})
.on('storage', window, function (e) {
console.log('localstorage changed', e);
})
.on('click', '.delete-datasource', function (e) {
e.preventDefault();
e.stopPropagation();
$(this).parent().parent().remove();
localStorage['query.datasources'] = $('.datasources').html();
})
.on('click', '.datasources a', function (e) {
e.preventDefault();
$datasource.text($(this).find('.name').text());
localStorage['query.datasource'] = $datasource.text();
localStorage['query.datasources'] = $('.datasources').html();
})
.on('click', '.add-datasource', function (e) {
e.preventDefault();
var dsname = prompt('Datasource name?', '');
if (dsname.length > 0) {
$('.datasources').append('<li><a href="##"><button type="button" class="close delete-datasource" aria-hidden="true">&times;</button><span class="name">' + dsname + '</span></a></li>');
localStorage['query.datasources'] = $('.datasources').html();
}
});
loadHistory();
$datasource.text(localStorage['query.datasource'] || '<none>');
if (localStorage['query.datasources']) {
$('.datasources').html(localStorage['query.datasources']);
}
});
})(jQuery)
</script>
</body>
</html></cfoutput>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment