Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
Signed-off-by: Byron Ruth <b@devel.io>
  • Loading branch information
bruth committed Aug 12, 2015
0 parents commit bcfe0e1
Show file tree
Hide file tree
Showing 9 changed files with 617 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
.DS_Store
*.sw?
profile.cov
profile.tmp
27 changes: 27 additions & 0 deletions Dockerfile
@@ -0,0 +1,27 @@
FROM golang:1.4

ENV LD_LIBRARY_PATH /go/src/github.com/chop-dbhi/sql-agent/lib/oracle/instantclient_12_1
ENV ORACLE_HOME /go/src/github.com/chop-dbhi/sql-agent/lib/oracle/instantclient_12_1

RUN apt-get update -qq
RUN apt-get install libaio1 pkg-config -y

RUN mkdir -p /go/src/github.com/chop-dbhi/sql-agent

WORKDIR /go/src/github.com/chop-dbhi/sql-agent
ADD . /go/src/github.com/chop-dbhi/sql-agent
RUN cp ./lib/oracle/oci8.pc /usr/lib/pkgconfig/

WORKDIR ./lib/oracle
RUN tar zxf instantclient_12_1.tar.gz

WORKDIR instantclient_12_1
RUN ln -s libclntsh.so.12.1 libclntsh.so
RUN ln -s libocci.so.12.1 libocci.so

WORKDIR /go/src/github.com/chop-dbhi/sql-agent
RUN make install
RUN make build

ENTRYPOINT ["/go/bin/sql-agent"]
CMD ["-host", "0.0.0.0"]
24 changes: 24 additions & 0 deletions LICENSE
@@ -0,0 +1,24 @@
Copyright (c) 2015 The Children's Hospital of Philadelphia and individual contributors.

All rights reserved.

Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
41 changes: 41 additions & 0 deletions Makefile
@@ -0,0 +1,41 @@
all: install

clean:
go clean ./...

doc:
godoc -http=:6060

install:
go get github.com/jmoiron/sqlx
go get github.com/lib/pq
go get github.com/denisenkom/go-mssqldb
go get github.com/go-sql-driver/mysql
go get github.com/mattn/go-sqlite3
go get github.com/mattn/go-oci8

test-install: install
go get golang.org/x/tools/cmd/cover
go get github.com/mattn/goveralls

test:
go test -cover ./...

test-travis:
./test-cover.sh

bench:
go test -run=none -bench=. -benchmem ./...

build:
go build -o $(GOPATH)/bin/sql-agent ./cmd/sql-agent

fmt:
go vet ./...
go fmt ./...

lint:
golint ./...


.PHONY: test proto
76 changes: 76 additions & 0 deletions README.md
@@ -0,0 +1,76 @@
# SQL Agent

[![GoDoc](https://godoc.org/github.com/chop-dbhi/sql-agent?status.svg)](https://godoc.org/github.com/chop-dbhi/sql-agent)

SQL Agent is an HTTP service for executing ad-hoc queries on remote databases. The motivation for this service is to be part of a data monitoring process or system in which the query results will be evaluated against previous snapshots of the results.

The supported databases are:

- PostgreSQL
- MySQL, MariaDB
- Oracle
- Microsoft SQL Server
- SQLite

In addition to the service, this repo also defines a `sqlagent` package for using in other Go programs.

## Install

At the moment, it is recommended to run the service using Docker because there are no pre-built binaries yet.

```
docker run -d -p 5000:5000 dbhi/sql-agent
```

## Usage

To execute a query, simply send a POST request with a payload containing the driver name of the database, connection information to with, and the SQL statement with optional parameters. The service will connect to the database, execute the query and return the results as a JSON-encoded array of maps (see [details](#Details) below).

**Request**

```json
{
"driver": "postgres",
"connection": {
"host": "localhost",
"user": "postgres"
},
"sql": "SELECT name FROM users WHERE zipcode = :zipcode",
"params": {
"zipcode": 18019
}
}
```

**Response**

```json
[
{
"name": "George"
},
...
]
```

### Connection Options

The core option names are standardized for ease of use.

- `host` - The host of the database.
- `port` - The port of the database.
- `user` - The user to connect with.
- `password` - The password to authenticate with.
- `database` - The name of the database to connect to. For SQLite, this will be a filesystem path. For Oracle, this would be the SID.

Other options that are supplied are passed query options if they are known, otherwise they are they ignored.

## Details

- Only `SELECT` statements are supported.
- Statements using parameters must use the `:param` syntax and must have a corresponding entry in the `params` map.
- The only standard

### Constraints

- Columns must be uniquely named, otherwise the conversion into a map will include only one of the values.
118 changes: 118 additions & 0 deletions cmd/sql-agent/main.go
@@ -0,0 +1,118 @@
package main

import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"

"github.com/chop-dbhi/sql-agent"
)

var usage = `SQL Agent - HTTP interface
This is an HTTP interface for the SQL Agent.
Run:
sql-agent [-host=<host>] [-port=<port>]
Example:
POST /
Content-Type application/json
{
"driver": "postgres",
"connection": {
"host": "pghost.org",
"port": 5432,
},
"sql": "SELECT * FROM users WHERE zipcode = :zipcode",
"parameters": {
"zipcode": 19104
}
}
`

const StatusUnprocessableEntity = 422

func init() {
flag.Usage = func() {
fmt.Println(usage)
flag.PrintDefaults()
}

log.SetFlags(log.LstdFlags | log.Lshortfile)
}

func main() {
var (
host string
port int
)

flag.StringVar(&host, "host", "localhost", "Host of the agent.")
flag.IntVar(&port, "port", 5000, "Port of the agent.")

flag.Parse()

addr := fmt.Sprintf("%s:%d", host, port)
log.Printf("* Listening on %s...\n", addr)

http.HandleFunc("/", handlerRequest)

log.Fatal(http.ListenAndServe(addr, nil))
}

type Payload struct {
Driver string
Connection map[string]interface{}
SQL string
Params map[string]interface{}
}

func handlerRequest(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
w.WriteHeader(http.StatusMethodNotAllowed)
return
}

var payload Payload

// Decode the body.
if err := json.NewDecoder(r.Body).Decode(&payload); err != nil {
w.WriteHeader(StatusUnprocessableEntity)
w.Write([]byte(fmt.Sprintf("could not decode JSON: %s", err)))
return
}

if _, ok := sqlagent.Drivers[payload.Driver]; !ok {
w.WriteHeader(StatusUnprocessableEntity)
w.Write([]byte(fmt.Sprintf("unknown driver: %v", payload.Driver)))
return
}

db, err := sqlagent.Connect(payload.Driver, payload.Connection)

if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(fmt.Sprintf("problem connecting to database: %s", err)))
return
}

records, err := sqlagent.Execute(db, payload.SQL, payload.Params)

if err != nil {
w.WriteHeader(http.StatusServiceUnavailable)
w.Write([]byte(fmt.Sprintf("error executing query: %s", err)))
return
}

if err = json.NewEncoder(w).Encode(records); err != nil {
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte(fmt.Sprintf("error encoding records: %s", err)))
return
}
}
Binary file added lib/oracle/instantclient_12_1.tar.gz
Binary file not shown.
10 changes: 10 additions & 0 deletions lib/oracle/oci8.pc
@@ -0,0 +1,10 @@
prefix=/go/src/github.com/chop-dbhi/sql-agent/lib/oracle/instantclient_12_1
libdir=${prefix}
includedir=${prefix}/sdk/include/

Name: OCI
Description: Oracle database engine
Version: 12.1
Libs: -L${libdir} -lclntsh
Libs.private:
Cflags: -I${includedir}

0 comments on commit bcfe0e1

Please sign in to comment.