2016-03-07 3 views
1

Я написал сценарий, который использует функцию потоковой обработки python. Я думаю, что проблема имеет какое-то отношение к потоковой передаче, потому что, когда я запускаю запрос из-за рабочего потока, он отлично работает. Я пытаюсь вставить некоторые вещи в базу данных, но столкнулся с некоторыми ДЕЙСТВИТЕЛЬНО фанковыми поведением.Python - Postgresql Неверная последовательность байтов для varchar - Weird Behavior

Позвольте мне упростить:

Запуск это работает:

cmd = "INSERT INTO cstanley_temp (device, host, ux, units) VALUES (%s, %s, %s, %s);" 
data = ("solaris-cdc", resultHOST[0], "UX10", 1,) 
sql.execute(cmd, data) 

Бегущий это не работает:

cmd = "INSERT INTO cstanley_temp (device, host, ux, units) VALUES (%s, %s, %s, %s);" 
data = ("solaris-cdc", resultHOST[0], "sdsdsdsdsdsd", 1,) 
sql.execute(cmd, data) 

Вот типы полей: device = VARCHAR host = VARCHAR ux = varchar units = INT

Это ошибка я получаю:

Exception in thread Thread-1: 
Traceback (most recent call last): 
    File "/usr/local/lib/python2.7/threading.py", line 801, in __bootstrap_inner 
    self.run() 
    File "/usr/local/lib/python2.7/threading.py", line 754, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/home/cstanley/scripts/vip/sun_audit.py", line 37, in workon 
    sql.execute(cmd, data) 
DataError: invalid byte sequence for encoding "UTF8": 0x86 
HINT: This error can also happen if the byte sequence does not match the encoding expected by the server, which is controlled by "client_encoding". 

Exception in thread Thread-2: 
Traceback (most recent call last): 
    File "/usr/local/lib/python2.7/threading.py", line 801, in __bootstrap_inner 
    self.run() 
    File "/usr/local/lib/python2.7/threading.py", line 754, in run 
    self.__target(*self.__args, **self.__kwargs) 
    File "/home/cstanley/scripts/vip/sun_audit.py", line 37, in workon 
    sql.execute(cmd, data) 
InternalError: current transaction is aborted, commands ignored until end of transaction block 

Вот полный код:

#!/usr/local/bin/python2.7 
import sys, os, string, threading 
import paramiko 
import psycopg2 
import time 

#paramiko.util.log_to_file("sun_audit.log") 

getCPU = "/usr/sbin/psrinfo -p" 
getMEM = "/usr/sbin/prtconf | grep \"Memory\" | awk '{ print $3 }'" 
getHOST = "hostname" 

class bcolors: 
    MAGENTA = '\033[95m' 
    YELLOW = '\033[93m' 
    ENDC = '\033[0m' 

def workon(host,sql): 

    #Connect to each host 
    ssh = paramiko.SSHClient() 
    key = paramiko.RSAKey.from_private_key_file("/home/cstanley/scripts/vip/cstanley") 
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
    ssh.connect(host, username='cstanley', pkey=key) 

    #Run Commands 
    stdinHOST, stdoutHOST, stderrHOST = ssh.exec_command(getHOST) 
    stdinCPU, stdoutCPU, stderrCPU = ssh.exec_command(getCPU) 
    stdinMEM, stdoutMEM, stderrMEM = ssh.exec_command(getMEM) 

    with threading.Lock(): 

     resultHOST = stdoutHOST.readlines() 
     #print "{0} {0} UX10 1".format(resultHOST[0].rstrip()) 
     cmd = "INSERT INTO cstanley_temp (device, host, ux, units) VALUES (%s, %s, %s, %s);" 
     data = ("solaris-cdc", resultHOST[0], "sdsdsdsdsdsd", 1,) 
     sql.execute(cmd, data) 

     resultCPU = stdoutCPU.readlines() 
     ux40 = (int(resultCPU[0].rstrip()) - 1) 
     if ux40 != 0: 
      #print "{0} {0} UX40 {1}".format(resultHOST[0].rstrip(),ux40) 
      cmd = "INSERT INTO cstanley_temp (device, host, ux, units) VALUES (%s, %s, %s, %s);" 
      data = ("solaris-cdc", resultHOST[0], "UX40", ux40,) 
      sql.execute(cmd, data) 

     resultMEM = stdoutMEM.readlines() 
     ux30 = (int(resultMEM[0].rstrip())/1024 - 2)/2 
     #print "{0} {0} UX30 {1}".format(resultHOST[0].rstrip(),ux30) 
     cmd = "INSERT INTO cstanley_temp (device, host, ux, units) VALUES (%s, %s, %s, %s);" 
     data = ("solaris-cdc", resultHOST[0], "UX30", ux30,) 
     sql.execute(cmd, data) 

     ssh.close() 

def main(): 

    #date = (time.strftime("%Y-%m-%d")) 

    #Define our connection string 
    conn_string = "host='REMOVED' dbname='REMOVED' user='REMOVED' password='REMOVED' connect_timeout=3" 

    # print the connection string we will use to connect 
    #print bcolors.MAGENTA + 'Connecting to database\n ->%s' % (conn_string) + bcolors.ENDC + "\n" 

    # get a connection, if a connect cannot be made an exception will be raised here 
    conn = psycopg2.connect(conn_string) 

    # conn.cursor will return a cursor object, you can use this cursor to perform queries 
    sql = conn.cursor() 
    print bcolors.YELLOW + "Inserting Solaris information into table.\n" + bcolors.ENDC 

    with open('/home/cstanley/scripts/vip/sun_ip') as ip: 
     hosts = ip.read().splitlines() 

    threads = [] 
    for h in hosts: 
     t = threading.Thread(target=workon, args=(h,sql,)) 
     t.start() 
     threads.append(t) 
    for t in threads: 
     t.join() 

    conn.commit() 
    sql.close() 
    conn.close() 

if __name__ == "__main__": 
    main() 

Пытаясь выяснить, что здесь происходит. Почему он работает, когда я ввожу UX10, но не когда я ввожу sdsdsdsdsdsd? Я даже попытался заменить его solaris-cdc так же, как в первой части запроса, но это также не удается. Что происходит в мире!?

ответ

1

Ошибка, кажется, говорит: вы пытаетесь вставить некоторые Python 2 str с двоичным кодом в столбец varchar, когда PostgreSQL ожидал, что будет указан нужный кодированный UFF-8. Либо это происходит от resultHOST[0] промежутков, или, возможно, у вас есть какой-то невидимый управляющий символ в коде в "sdsdsdsdsdsd" строки:

>>> print u"here be ma\x86gic" 
here be magic 

Однако реальная причина может быть, что в соответствии с psycopg2 documentation,

Курсоры не являются потокобезопасными: многопоточное приложение может создавать множество курсоров из одного и того же соединения и использовать каждый курсор из одного потока. См. Thread and process safety.

Таким образом, вы должны создать новый курсор для каждого потока. Вместо прохождения sql в качестве аргумента workon, просто создать новый курсор внутри метода workon с утверждением

sql = conn.cursor() 

Кроме того, не должно быть никакой необходимости для блокировки, так как с помощью одного соединения с несколькими курсорами является поточно-безопасным, как есть.

+0

Как «UX10» нормальный, а «sdsdsdsdsd» - нет? Кроме того, как работает «solaris-cdc» на одном поле, а другое поле «solaris-cdc» не работает? Оба поля являются одинаковыми. Очевидно, что это проблема, но каково решение? Мне кажется, что потоки каким-то образом ставят двоичные данные там, где это не должно. Вы видите, что выполнение двух EXACT-запросов вызывает разные проблемы, когда поле является «UX10» и «sdsdsdsdsd». Проблема очевидна, да postgres ожидает UTF-8 и получает что-то еще.Это не мой вопрос - мой вопрос в том, почему мой скрипт отправляет двоичный файл. –

+0

Я набрал sdsdsdsdsd вручную - и при смене его на 'UX10' он работает. Таким образом, из этого вышло из resultHOST [0], я бы ожидал, что он все равно выдает ошибку, когда поле было изменено на 'UX10' –

+0

Можете ли вы получить MVCE этого? На вопрос, конечно, нет минимального, полного и проверяемого примера - далеко от него –