Executing Python script from PHP and insert in mysql - python

I have a php script that executes a python script and returns the data back and it is stored in mysql. It's working fine but when the data is stored in the database it inserts an additional blank row. My question would be, how could I make so that it stores only the actual data I recieve.
This is part of the python script
##ser.write(sync)
ser.write(counters)
a = ser.read(30)
state = binascii.hexlify(a)
asd = re.sub(rb'([0-9, a-z, A-Z])(?!$)', rb'\1,', state)
url = 'http://127.0.0.1/sastest/meters.php'
x = requests.post(url, data = asd)
print(asd)
And this is from the PHP
passthru("meters.py");
$incomingData = file_get_contents("php://input");
$qry1 = "INSERT INTO machtest(data)
values('".$incomingData."')";
mysqli_query($conn,$qry1);

From comments we discover the overall process:
When I call meters.php it activates meters.py. meters.py interrogates a devices and sends the data back to meters.php
Because PHP's passthru does not support output return but a similar function exec does as array object with each line as elements, use that instead and do not have Python post back a response. Of course, always run parameterization when interacting with databases and passing input values.
Python (meters.py)
ser.write(counters)
a = ser.read(30)
state = binascii.hexlify(a)
asd = re.sub(rb'([0-9, a-z, A-Z])(?!$)', rb'\1,', state)
print(asd)
PHP (meters.php)
// USE output ARG
exec(command = "meters.py", output = $incomingData);
// USE PARAMETERIZATION
$qry = "INSERT INTO machtest (data) VALUES (%s)";
$stmt = mysqli_prepare($qry);
mysqli_stmt_bind_param($stmt, "s", $incomingData[0]);
mysqli_stmt_execute($stmt);
See mysqli prepared statement docs
Alternatively, have Python run all processing including device and database interaction. Then, have PHP call the .py script:
Python (meters.py)
import mysql.connector # USE ANY MySQL DB-API. THIS IS AN EXAMPLE
...
### INTERROGATE DEVICE
ser.write(counters)
a = ser.read(30)
state = binascii.hexlify(a)
asd = re.sub(rb'([0-9, a-z, A-Z])(?!$)', rb'\1,', state)
### APPEND TO DATABASE
# OPEN CONNECTION AND CURSOR
conn = mysql.connector.connect(host='localhost', database='mydatabase',
user='root', password='pwd')
cur = conn.cursor()
# USE PARAMETERIZATION
qry = "INSERT INTO machtest (data) VALUES (%s)"
cur.execute(qry, (asd,))
conn.commit()
cur.close()
conn.close()
See MySQL cursor execute docs
PHP (meters.php)
// NO NEED FOR output
passthru(command = "meters.py");

Related

How to retrieve an output parameter of a stored procedure?

I'm trying to execute an SQL stored procedure which does some inserts an updates, and I pass a parameter called lcLogSessionId to it. During the execution of the procedure this parameter is set to 1 if there are errors, and remains to 0 if everything worked correctly.
In my python script I need to retrieve that value at the end of the execution of the stored procedure.
This is my code:
stored_proc = "Exec [APP].[dataImport] #lcLogSessionId = %s"%(0)
conn = pyodbc.connect(connection_string, autocommit = True)
cursor = conn.cursor()
cursor.execute(stored_proc)
I've tried to fetch the cursor with row = cursor.fetchone(), but i get an error which says "No results. Previous SQL was not a query".
Is there a way to get the value of lcLogSessionId?
pyodbc does not currently implement the optional .callproc() method, so a workaround is required to retrieve output parameters and return values. For SQL Server that involves an anonymous code block to EXEC the stored procedure and then SELECT the values, e.g.,
sql = """\
DECLARE #out nvarchar(max);
EXEC [dbo].[test_for_pyodbc] #param_in = ?, #param_out = #out OUTPUT;
SELECT #out AS the_output;
"""
params = ("Burma!", )
crsr.execute(sql, params)
rows = crsr.fetchall()
while rows:
print(rows)
if crsr.nextset():
rows = crsr.fetchall()
else:
rows = None
More details at the pyodbc wiki:
https://github.com/mkleehammer/pyodbc/wiki/Calling-Stored-Procedures#output-parameters-and-return-values

How to i read the contents of Oracle stored procedures using Python

I am trying to read the contents/code of a stored procedure using python.
i used cx_Oracle function to establish the connection with oracle database.
here is the code
import cx_Oracle as co
import pandas as pd
dsn_tsn = co.makedsn(ip,port,SID)
db=co.connect(username,password,dsn_tsn)
cursor = db.cursor()
cursor.callproc(procedure_name,['argument']) # will be me result of the procedure.
However, i am trying to read the code of procedure itself. Is there any function to do that ?
You can call DBMS_METADATA.GET_DDL function from your code in such a way
import cx_Oracle
db = cx_Oracle.connect("<uname>/<pwd>#<host>:<port>/<service_name>")
cursor = db.cursor()
def OutputTypeHandler(cursor, name, defaultType, size, precision, scale):
if defaultType == cx_Oracle.CLOB:
return cursor.var(cx_Oracle.LONG_STRING, arraysize = cursor.arraysize)
cursor.outputtypehandler = OutputTypeHandler
cursor.execute("SELECT DBMS_METADATA.GET_DDL('PROCEDURE', :PrcName) FROM DUAL",
PrcName="MY_LITTLE_PROC")
print("returned DDL is :",cursor.fetchall())
Code of stored procedures can be accessed via user_source view. So, if you query it, you'll see what you want. Here's how:
SQL> create or replace procedure p_test is
2 begin
3 null;
4 end;
5 /
Procedure created.
SQL> desc user_source
Name Null? Type
----------------------------------------- -------- ----------------------------
NAME VARCHAR2(30)
TYPE VARCHAR2(12)
LINE NUMBER
TEXT VARCHAR2(4000)
SQL> select text from user_source where name = 'P_TEST' and type = 'PROCEDURE';
TEXT
--------------------------------------------------------------------------------
procedure p_test is
begin
null;
end;
SQL>
Though, as I don't speak Python, I can't assist in actual code you need to use there. The last select I wrote is what you need; I hope you'll manage to use it. Good luck!
import oracledb
db = oracledb.connect("<uname>/<pwd>#<host>:<port>/<service_name>")
cursor = db.cursor()
cursor.execute("SELECT DBMS_METADATA.GET_DDL('PROCEDURE', 'PROC_NAME', 'OWNER') FROM DUAL")
c = cursor.fetchall()
print( c[0][0] )
# To save on file
sample = open('samplefile.txt', 'w')
print(c[0][0], file = sample)
sample.close()
Change connection details, PROC_NAME and OWNER and run.

Python PYODBC - Previous SQL was not a query

I have the following python code, it reads through a text file line by line and takes characters x to y of each line as the variable "Contract".
import os
import pyodbc
cnxn = pyodbc.connect(r'DRIVER={SQL Server};CENSORED;Trusted_Connection=yes;')
cursor = cnxn.cursor()
claimsfile = open('claims.txt','r')
for line in claimsfile:
#ldata = claimsfile.readline()
contract = line[18:26]
print(contract)
cursor.execute("USE calms SELECT XREF_PLAN_CODE FROM calms_schema.APP_QUOTE WHERE APPLICATION_ID = "+str(contract))
print(cursor.fetchall())
When including the line cursor.fetchall(), the following error is returned:
Programming Error: Previous SQL was not a query.
The query runs in SSMS and replace str(contract) with the actual value of the variable results will be returned as expected.
Based on the data, the query will return one value as a result formatted as NVARCHAR(4).
Most other examples have variables declared prior to the loop and the proposed solution is to set NO COUNT on, this does not apply to my problem so I am slightly lost.
P.S. I have also put the query in its own standalone file without the loop to iterate through the file in case this was causing the problem without success.
In your SQL query, you are actually making two commands: USE and SELECT and the cursor is not set up with multiple statements. Plus, with database connections, you should be selecting the database schema in the connection string (i.e., DATABASE argument), so TSQL's USE is not needed.
Consider the following adjustment with parameterization where APPLICATION_ID is assumed to be integer type. Add credentials as needed:
constr = 'DRIVER={SQL Server};SERVER=CENSORED;Trusted_Connection=yes;' \
'DATABASE=calms;UID=username;PWD=password'
cnxn = pyodbc.connect(constr)
cur = cnxn.cursor()
with open('claims.txt','r') as f:
for line in f:
contract = line[18:26]
print(contract)
# EXECUTE QUERY
cur.execute("SELECT XREF_PLAN_CODE FROM APP_QUOTE WHERE APPLICATION_ID = ?",
[int(contract)])
# FETCH ROWS ITERATIVELY
for row in cur.fetchall():
print(row)
cur.close()
cnxn.close()

How to get sanitized postgres SQL string in python for later use?

I have a query that I want to append to a file (to generate a list of queries) that will be executed later.
location_filter="SELECT id FROM developers WHERE location='%s'"
out_file.write((location_filter, (location)))
But the output that gets written can't be executed in pgadmin:
("SELECT id FROM developers WHERE location='%s'", u'Seattle')
How can I safely generate this statement?
conn = psycopg2.connect(database='cpn')
cur = conn.cursor()
location_filter = "SELECT id FROM developers WHERE location = %s"
out_file.write(cur.mogrify(location_filter, (location,)))

Pure Python Backup of SQLite3 In-Memory Database to Disk

Without installing additional modules, how can I use the SQLite backup API to backup an in-memory database to an on-disk database? I have managed to successfully perform a disk-to-disk backup, but passing the already-extant in-memory connection to the sqlite3_backup_init function appears to be the problem.
My toy example, adapted from https://gist.github.com/achimnol/3021995 and cut down to the minimum, is as follows:
import sqlite3
import ctypes
# Create a junk in-memory database
sourceconn = sqlite3.connect(':memory:')
cursor = sourceconn.cursor()
cursor.execute('''CREATE TABLE stocks
(date text, trans text, symbol text, qty real, price real)''')
cursor.execute("INSERT INTO stocks VALUES ('2006-01-05','BUY','RHAT',100,35.14)")
sourceconn.commit()
target = r'C:\data\sqlite\target.db'
dllpath = u'C:\\Python27\DLLs\\sqlite3.dll'
# Constants from the SQLite 3 API defining various return codes of state.
SQLITE_OK = 0
SQLITE_ERROR = 1
SQLITE_BUSY = 5
SQLITE_LOCKED = 6
SQLITE_OPEN_READONLY = 1
SQLITE_OPEN_READWRITE = 2
SQLITE_OPEN_CREATE = 4
# Tweakable variables
pagestocopy = 20
millisecondstosleep = 100
# dllpath = ctypes.util.find_library('sqlite3') # I had trouble with this on Windows
sqlitedll = ctypes.CDLL(dllpath)
sqlitedll.sqlite3_backup_init.restype = ctypes.c_void_p
# Setup some ctypes
p_src_db = ctypes.c_void_p(None)
p_dst_db = ctypes.c_void_p(None)
null_ptr = ctypes.c_void_p(None)
# Check to see if the first argument (source database) can be opened for reading.
# ret = sqlitedll.sqlite3_open_v2(sourceconn, ctypes.byref(p_src_db), SQLITE_OPEN_READONLY, null_ptr)
#assert ret == SQLITE_OK
#assert p_src_db.value is not None
# Check to see if the second argument (target database) can be opened for writing.
ret = sqlitedll.sqlite3_open_v2(target, ctypes.byref(p_dst_db), SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, null_ptr)
assert ret == SQLITE_OK
assert p_dst_db.value is not None
# Start a backup.
print 'Starting backup to SQLite database "%s" to SQLite database "%s" ...' % (sourceconn, target)
p_backup = sqlitedll.sqlite3_backup_init(p_dst_db, 'main', sourceconn, 'main')
print ' Backup handler: {0:#08x}'.format(p_backup)
assert p_backup is not None
# Step through a backup.
while True:
ret = sqlitedll.sqlite3_backup_step(p_backup, pagestocopy)
remaining = sqlitedll.sqlite3_backup_remaining(p_backup)
pagecount = sqlitedll.sqlite3_backup_pagecount(p_backup)
print ' Backup in progress: {0:.2f}%'.format((pagecount - remaining) / float(pagecount) * 100)
if remaining == 0:
break
if ret in (SQLITE_OK, SQLITE_BUSY, SQLITE_LOCKED):
sqlitedll.sqlite3_sleep(millisecondstosleep)
# Finish the bakcup
sqlitedll.sqlite3_backup_finish(p_backup)
# Close database connections
sqlitedll.sqlite3_close(p_dst_db)
sqlitedll.sqlite3_close(p_src_db)
I receive an error ctypes.ArgumentError: argument 3: <type 'exceptions.TypeError'>: Don't know how to convert parameter 3 on line 49 (p_backup = sqlitedll.sqlite3_backup_init(p_dst_db, 'main', sourceconn, 'main')). Somehow, I need to pass a reference to the in-memory database to that sqlite3_backup_init function.
I do not know enough C to grasp the specifics of the API itself.
Setup: Windows 7, ActiveState Python 2.7
It looks like as of Python 3.7, this functionality is available within the standard library. Here are some examples copied directly out of the official docs:
Example 1, copy an existing database into another:
import sqlite3
def progress(status, remaining, total):
print(f'Copied {total-remaining} of {total} pages...')
con = sqlite3.connect('existing_db.db')
bck = sqlite3.connect('backup.db')
with bck:
con.backup(bck, pages=1, progress=progress)
bck.close()
con.close()
Example 2, copy an existing database into a transient copy:
import sqlite3
source = sqlite3.connect('existing_db.db')
dest = sqlite3.connect(':memory:')
source.backup(dest)
To answer your specific question of backing up an in-memory database to disk, it looks like this works. Here's a quick script using the standard library backup method:
import sqlite3
source = sqlite3.connect(':memory:')
dest = sqlite3.connect('backup.db')
c = source.cursor()
c.execute("CREATE TABLE test(id INTEGER PRIMARY KEY, msg TEXT);")
c.execute("INSERT INTO test VALUES (?, ?);", (1, "Hello World!"))
source.commit()
source.backup(dest)
dest.close()
source.close()
And the backup.db database can be loaded into sqlite3 and inspected:
$ sqlite3 backup.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> .schema
CREATE TABLE test(id INTEGER PRIMARY KEY, msg TEXT);
sqlite> SELECT * FROM test;
1|Hello World!
An in-memory database can be accessed only through the SQLite library that created it (in this case, Python's built-in SQLite).
Python's sqlite3 module does not give access to the backup API, so it is not possible to copy an in-memory database.
You would need to install an additional module, or use an on-disk database in the first place.
While this isn't strictly a solution to your questions (as it's not using the backup API) it serves as a minimal effort approach and works well for small in memory databases.
import os
import sqlite3
database = sqlite3.connect(':memory:')
# fill the in memory db with your data here
dbfile = 'dbcopy.db'
if os.path.exists(dbfile):
os.remove(dbfile) # remove last db dump
new_db = sqlite3.connect(dbfile)
c = new_db.cursor()
c.executescript("\r\n".join(database.iterdump()))
new_db.close()
#cl is wrong. I solved this problem using ctypes to extract the underlying C pointer of a Python connection object and created a small package: https://pypi.org/project/sqlite3-backup/
Source code is at https://sissource.ethz.ch/schmittu/sqlite3_backup

Categories

Resources