PLPGSQL using single quotes in function call (python) - python

I am having problems when using single quotes in a insert value for a plpgsql function
It looks like this:
"AND (u.firstname LIKE 'koen') OR
(u.firstname LIKE 'dirk')"
This is done with python
I have tried \' and '' and ''' and '''' and ''''' and even '''''''
none of them seem to be working and return the following error:
[FAIL][syntax error at or near "koen"
LINE 1: ...'u.firstname', 'ASC', 'AND (u.firstname LIKE 'koe...
Any help is appreciated!
Thanks a lot!
======================== EDIT =========================
Sorry! here is my plpgsql function:
CREATE FUNCTION get_members(IN in_company_uuid uuid, IN in_start integer, IN in_limit integer, IN in_sort character varying, IN in_order character varying, IN in_querystring CHARACTER VARYING, IN in_filterstring CHARACTER VARYING, IN OUT out_status integer, OUT out_status_description character varying, OUT out_value character varying[]) RETURNS record
LANGUAGE plpgsql
AS $$DECLARE
temp_record RECORD;
temp_out_value VARCHAR[];
--temp_member_struct MEMBER_STRUCT;
temp_iterator INTEGER := 0;
BEGIN
FOR temp_record IN EXECUTE '
SELECT DISTINCT ON
(' || in_sort || ')
u.user_uuid,
u.firstname,
u.preposition,
u.lastname,
array_to_string_ex(ARRAY(SELECT email FROM emails WHERE user_uuid = u.user_uuid)) as emails,
array_to_string_ex(ARRAY(SELECT mobilenumber FROM mobilenumbers WHERE user_uuid = u.user_uuid)) as mobilenumbers,
array_to_string_ex(ARRAY(SELECT c.name FROM targetgroupusers AS tgu LEFT JOIN membercategories as mc ON mc.targetgroup_uuid = tgu.targetgroup_uuid LEFT JOIN categories AS c ON mc.category_uuid = c.category_uuid WHERE tgu.user_uuid = u.user_uuid)) as categories,
array_to_string_ex(ARRAY(SELECT color FROM membercategories WHERE targetgroup_uuid IN(SELECT targetgroup_uuid FROM targetgroupusers WHERE user_uuid = u.user_uuid))) as colors
FROM
membercategories AS mc
LEFT JOIN
targetgroups AS tg
ON
tg.targetgroup_uuid = mc.targetgroup_uuid
LEFT JOIN
targetgroupusers AS tgu
ON
tgu.targetgroup_uuid = tg.targetgroup_uuid
LEFT JOIN
users AS u
ON
u.user_uuid = tgu.user_uuid
WHERE
mc.company_uuid = ''' || in_company_uuid || '''
' || in_querystring || '
' || in_filterstring || '
ORDER BY
' || in_sort || ' ' || in_order || '
OFFSET
' || in_start || '
LIMIT
' || in_limit
LOOP
temp_out_value[temp_iterator] = ARRAY[temp_record.user_uuid::VARCHAR(36),
temp_record.firstname,
temp_record.preposition,
temp_record.lastname,
temp_record.emails,
temp_record.mobilenumbers,
temp_record.categories,
temp_record.colors];
temp_iterator = temp_iterator+1;
END LOOP;
out_status := 0;
out_status_description := 'Members retrieved';
out_value := temp_out_value;
RETURN;
END$$;
Here is how i call the function:
def get_members(companyuuid, start, limit, sort, order, querystring = None, filterstring = None):
logRequest()
def doWork(cursor):
if not companyuuid:
raise Exception("companyuuid cannot be None!")
queryarray = [str(s) for s in querystring.split("|")]
queryfields = ['firstname', 'preposition', 'lastname', 'emails', 'mobilenumbers']
temp_querystring = ""
for j in xrange(len(queryfields)):
for i in xrange(len(queryarray)):
temp_querystring += "(u.%s LIKE ''%%%s%'') OR "%(queryfields[j], queryarray[i])
temp_querystring = "AND %s"%temp_querystring.rstrip(" OR ")
temp_filterstring = filterstring
print "querystring: %s"%temp_querystring
heizoodb.call(cursor=cursor,
scheme="public",
function="get_members",
functionArgs=(companyuuid, start, limit, sort, order, temp_querystring, temp_filterstring),
returnsValue=True)
And my latest error =D
com.gravityzoo.core.libs.sql.PostgreSQLDB.runSQLTransaction: not enough arguments for format string, result=[None]
SQLinjection to be added later ;)
Thanks!

I don't know Python well, but it probably supports data binding where you first prepare a statement (and you don't need quotes around the question marks there):
prepare("..... AND (u.firstname LIKE ?) OR (u.firstname LIKE ?)")
and then you call execute('koen', 'dirk') or whatever that function is called in Python.

Related

PLY Lex: ID could be anything

I have a following simple format:
BLOCK ID {
SUBBLOCK ID {
SUBSUBBLOCK ID {
SOME STATEMENTS;
};
};
};
I configured ply to work with this format. But the issue is that ID could be any string including "BLOCK", "SUBBLOCK", etc.
In the lexer I define ID as:
#TOKEN(r'[a-zA-Z_][a-zA-Z_0-9]*')
def t_ID(self, t):
t.type = self.keyword_map.get(t.value, "ID")
return t
But it means that BLOCK word will not be allowed as a block name.
How I can overcome this issue?
The easiest solution is to create a non-terminal name to be used instead of ID in productions which need a name, such as block : BLOCK name braced_statements:
# Docstring is added later
def p_name(self, p):
p[0] = p[1]
Then you compute the productions for name and assign them to p_name's docstring by executing this before you generate the parser:
Parser.p_name.__doc__ = '\n| '.join(
['name : ID']
+ list(Lexer.keyword_map.values())
)
I probably dont understand your question
but i think something like the following would work (its been a long time since
I messed with PLY so keep in mind this is pseudocode
FUNCTION_ARGS = zeroOrMore(lazy('STATEMENT'),sep=',')
FUNCTION_CALL = t_ID + lparen + FUNCTION_ARGS + rparen
STATEMENT= FUNCTION_CALL | t_Literal | t_ID
SUBBLOCK = Literal('SUBBLOCK') + t_ID + lbrace + STATEMENT + rbrace
BLOCK = Literal('BLOCK') + lbrace + oneOrMore(SUBBLOCK) + rbrace

PyParsing: parse if not a keyword

I am trying to parse a file as follows:
testp.txt
title = Test Suite A;
timeout = 10000
exp_delay = 500;
log = TRUE;
sect
{
type = typeA;
name = "HelloWorld";
output_log = "c:\test\out.log";
};
sect
{
name = "GoodbyeAll";
type = typeB;
comm1_req = 0xDEADBEEF;
comm1_resp = (int, 1234366);
};
The file first contains a section with parameters and then some sects. I can parse a file containing just parameters and I can parse a file just containing sects but I can't parse both.
from pyparsing import *
from pathlib import Path
command_req = Word(alphanums)
command_resp = "(" + delimitedList(Word(alphanums)) + ")"
kW = Word(alphas+'_', alphanums+'_') | command_req | command_resp
keyName = ~Literal("sect") + Word(alphas+'_', alphanums+'_') + FollowedBy("=")
keyValue = dblQuotedString.setParseAction( removeQuotes ) | OneOrMore(kW,stopOn=LineEnd())
param = dictOf(keyName, Suppress("=")+keyValue+Optional(Suppress(";")))
node = Group(Literal("sect") + Literal("{") + OneOrMore(param) + Literal("};"))
final = OneOrMore(node) | OneOrMore(param)
param.setDebug()
p = Path(__file__).with_name("testp.txt")
with open(p) as f:
try:
x = final.parseFile(f, parseAll=True)
print(x)
print("...")
dx = x.asDict()
print(dx)
except ParseException as pe:
print(pe)
The issue I have is that param matches against sect so it expects a =. So I tried putting in ~Literal("sect") in keyName but that just leads to another error:
Exception raised:Found unwanted token, "sect", found '\n' (at char 188), (line:4, col:56)
Expected end of text, found 's' (at char 190), (line:6, col:1)
How do I get it use one parse method for sect and another (param) if not sect?
My final goal would be to have the whole lot in a Dict with the global params and sects included.
EDIT
Think I've figured it out:
This line...
final = OneOrMore(node) | OneOrMore(param)
...should be:
final = ZeroOrMore(param) + ZeroOrMore(node)
But I wonder if there is a more structured way (as I'd ultimately like a dict)?

Escape reserved characters in a list by adding backslash in front of it

reserved_chars = "? & | ! { } [ ] ( ) ^ ~ * : \ " ' + -"
list_vals = ['gold-bear#gmail.com', 'P&G#dom.com', 'JACKSON! BOT', 'annoying\name']
What is that fastest way to loop through every element in a list and add a \ in front of the reserved character if one of the elements contains them?
desired output:
fixed_list = ['gold\-bear#gmail.com', 'P\&G#dom.com', 'JACKSON\! BOT', 'annoying\\name']
You could make a translation table with str.maketrans() and pass that into translate. This takes a little setup, but you can reuse the translation table and it's quite fast:
reserved_chars = '''?&|!{}[]()^~*:\\"'+-'''
list_vals = ['gold-bear#gmail.com', 'P&G#dom.com', 'JACKSON! BOT', 'annoying\\name']
# make trans table
replace = ['\\' + l for l in reserved_chars]
trans = str.maketrans(dict(zip(reserved_chars, replace)))
# translate with trans table
fixed_list = [s.translate(trans) for s in list_vals]
print("\n".join(fixed_list))
Prints:
gold\-bear#gmail.com
P\&G#dom.com
JACKSON\! BOT
annoying\\name
There is no fast way - you got strings, strings are immuteable, you need to create new ones.
Probably best way is to build your own translation dictionary and do the grunt work yourself:
reserved = """? & | ! { } [ ] ( ) ^ ~ * : \ " ' + -"""
tr = { c:f"\\{c}" for c in reserved}
print(tr)
data = ['gold-bear#gmail.com', 'P&G#dom.com', 'JACKSON! BOT', 'annoying\name']
transformed = [ ''.join(tr.get(letter,letter) for letter in word) for word in data]
for word in transformed:
print(word)
Output:
# translation dictionary
{'?': '\\?', ' ': '\\ ', '&': '\\&', '|': '\\|', '!': '\\!', '{': '\\{',
'}': '\\}', '[': '\\[', ']': '\\]', '(': '\\(', ')': '\\)', '^': '\\^',
'~': '\\~', '*': '\\*', ':': '\\:', '\\': '\\\\', '"': '\\"', "'": "\\'",
'+': '\\+', '-': '\\-'}
# transformed strings
gold\-bear#gmail.com
P\&G#dom.com
JACKSON\!\ BOT
annoying
ame
Sidenotes:
Your example missed to escape the space inside 'JACKSON\! BOT'.
The repl() of the transformed list looks "wrongly" escaped because when printing it escapes each '\' itself again - whats being printed see wordlist
Definitely not the fastest, but could be the easiest to code. Make a regex that does it for you, and run re.sub, like this:
import re
reserved_chars = "?&|!{}[]()^~*:\\\"'+-"
replace_regex = "([" + ''.join('\\x%x' % ord(x) for x in reserved_chars) + "])"
list_vals = ['gold-bear#gmail.com', 'P&G#dom.com', 'JACKSON! BOT', r'annoying\name']
escaped_vals = [re.sub(replace_regex, r"\\\1", x) for x in list_vals]
Again, just to clarify, regexes are SLOW.

How to combine values in dict to new key/value pair, replacing None with empty string?

I have a dictionary (d) like so:
d = {
'[primary_number]': '12345',
'[street_name]': 'Main',
'[street_predirection]': 'NW',
'[street_postdirection]': None,
'[street_suffix]': 'St',
'[secondary_number]': None,
'[secondary_designator]': None,
'[extra_secondary_number]': None,
'[zipcode]': '12345'
}
And I would like to create a new Key/Value pair called AddressStr that combines several (but not all) of the fields in d. I am trying to combine it with the following code:
d['AddressStr'] = d["[zipcode]"] + \
d["[street_name]"] + \
d["[primary_number]"] + \
d["[secondary_number]"] + \
d["[street_predirection]"] + \
d["[street_postdirection]"] + \
d["[street_suffix]"]
However, this produces the error:
can only concatenate str (not "NoneType") to str
Because [street_postdirection] = None. Ideally, I would like to just have a check/replace to change the None values in those 7 fields to '', but I'm not quite sure how to do that. I'd also like to do in place during the creation of d['AddressStr'], but if that's not possible I'm OK with that.
You can join the values that are not None:
keys = ["[zipcode]", "[street_name]", "[primary_number]",
"[secondary_number]", "[street_predirection]", "[street_postdirection]",
"[street_suffix]"]
d['AddressStr'] = ' '.join([d[key] for key in keys if d[key] is not None])
You could use the str() method and use the property that None behaves as false on a boolean check:
d['AddressStr'] = str(d["[zipcode]"] or '') + \
str(d["[street_name]"] or '') + \
str(d["[primary_number]"] or '') + \
str(d["[secondary_number]"] or '') + \
str(d["[street_predirection]"] or '') + \
str(d["[street_postdirection]"] or '') + \
str(d["[street_suffix]"] or '')

how to approach converting VBscript to Python code?

I've been asked by my boss to convert a piece of vb script, which is manually run every Friday into python, except he wants it automated. I'm new to programming and would like some help deciding how to begin with this problem. This will be my first real programming project and fortunatley there is no real time restriction.
Context: We have an ESRI Flexviewer for displaying maps in our organisation. The script in question takes polylines, calculates the angle of the line, then calculates the flow direction. It does this by using a to and from field within the polylines feature class and places direction arrows on the mid point of each pipe.
I've pasted the script below... its kind of long but any help would be much appreciated!
So what I'm asking for is a suggestion on how to attack this. Just a start. Do i list out the main processes the VB script is using? Do i draw a flow diagram and being writing out psydo code for python? should i identify the main processes, for example the loops? and use that as a framework to begin?
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports ESRI.ArcGIS.ADF.BaseClasses
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.Display
Imports ESRI.ArcGIS.Framework
Imports ESRI.ArcGIS.Catalog
Imports ESRI.ArcGIS.CatalogUI
Imports ESRI.ArcGIS.Carto
Imports ESRI.ArcGIS.Geometry
Imports ESRI.ArcGIS.Geodatabase
Imports ESRI.ArcGIS.esriSystem
Imports ESRI.ArcGIS.SystemUI
Imports System.Windows
<ComClass(CmdFlowCreation.ClassId, CmdFlowCreation.InterfaceId, CmdFlowCreation.EventsId), _
ProgId("FlowArrows.CmdFlowCreation")> _
Public NotInheritable Class CmdFlowCreation
Inherits BaseCommand
#Region "COM GUIDs"
' These GUIDs provide the COM identity for this class
' and its COM interfaces. If you change them, existing
' clients will no longer be able to access the class.
Public Const ClassId As String = "35ac8cdc-4893-42d5-97ad-f41804dcb618"
Public Const InterfaceId As String = "ec8ac176-19cc-4979-a5ca-4f7cf80bb37b"
Public Const EventsId As String = "af685c91-ec0a-4ccd-ad21-56f9811c5f72"
#End Region
#Region "COM Registration Function(s)"
<ComRegisterFunction(), ComVisibleAttribute(False)> _
Public Shared Sub RegisterFunction(ByVal registerType As Type)
' Required for ArcGIS Component Category Registrar support
ArcGISCategoryRegistration(registerType)
'Add any COM registration code after the ArcGISCategoryRegistration() call
End Sub
<ComUnregisterFunction(), ComVisibleAttribute(False)> _
Public Shared Sub UnregisterFunction(ByVal registerType As Type)
' Required for ArcGIS Component Category Registrar support
ArcGISCategoryUnregistration(registerType)
'Add any COM unregistration code after the ArcGISCategoryUnregistration() call
End Sub
#Region "ArcGIS Component Category Registrar generated code"
Private Shared Sub ArcGISCategoryRegistration(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
GxCommands.Register(regKey)
End Sub
Private Shared Sub ArcGISCategoryUnregistration(ByVal registerType As Type)
Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
GxCommands.Unregister(regKey)
End Sub
#End Region
#End Region
Private Const dDistance As Double = 0.5
Private Const bAsRatio As Boolean = True
Private m_application As IApplication
Dim pFClass As IFeatureClass
Public m_pPropertySet As ESRI.ArcGIS.esriSystem.IPropertySet 'SDE Connection Properties
Public m_pWS As IWorkspace
Public m_pWSF As IWorkspaceFactory
Public bContinue As Boolean
Public pLineLayer As IFeatureLayer
Public pPointLayer As IFeatureLayer
Public bCreate As Boolean
Public bUpdate As Boolean
' A creatable COM class must have a Public Sub New()
' with no parameters, otherwise, the class will not be
' registered in the COM registry and cannot be created
' via CreateObject.
Public Sub New()
MyBase.New()
' TODO: Define values for the public properties
MyBase.m_category = "PNCC ARCCatalog" 'localizable text
MyBase.m_caption = "Flow Creation" 'localizable text
MyBase.m_message = "Create flow arrows. 9.3" 'localizable text
MyBase.m_toolTip = "Flow Creation 9.3 (17-May-2010)" 'localizable text
MyBase.m_name = "FlowArrows.CmdFlowCreation" 'unique id, non-localizable (e.g. "MyCategory_ArcCatalogCommand")
Try
'TODO: change bitmap name if necessary
Dim bitmapResourceName As String = Me.GetType().Name + ".bmp"
' MyBase.m_bitmap = New Bitmap(Me.GetType(), bitmapResourceName)
MyBase.m_bitmap = Global.FlowArrows.My.Resources.BMPCmdFlowCreation
Catch ex As Exception
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap")
End Try
End Sub
'' Public ReadOnly Property Enabled() As Boolean Implements ESRI.ArcGIS.SystemUI.ICommand.Enabled
'' Dim mxDoc As IMxDocument
'' Dim layerCount As Integer
'' 'pApp is set in OnCreate
'' mxDoc = CType(m_pApp.Document, IMxDocument)
'' layerCount = mxDoc.FocusMap.LayerCount
'' If pLayerCount> 0 Then
'' Return True
'' Else
'' Return False
'' End If
'' End Property
'Private Property Get ICommand_Enabled() As Boolean
'ICommand_Enabled = True
'Dim pGxApplication As IGxApplication
'Dim pGxObject As IGxObject
'Dim pGxDataSet As IGxDataset
'Set pGxApplication = mApplication
'Set pGxObject = pGxApplication.SelectedObject
''
'If TypeOf pGxObject Is IGxDataset Then
' Set pGxDataSet = pGxObject
' If TypeOf pGxDataSet.Dataset Is IFeatureClass Then
'' Dim pFClass As IFeatureClass
' Set pFClass = pGxDataSet.Dataset
' If pFClass.ShapeType = esriGeometryPolyline Then
' ICommand_Enabled = True
' End If
' End If
'Else
' ICommand_Enabled = False
'End If
'End Property
Public Overrides Sub OnCreate(ByVal hook As Object)
If Not hook Is Nothing Then
m_application = CType(hook, IApplication)
'Disable if it is not ArcCatalog
If TypeOf hook Is IGxApplication Then
MyBase.m_enabled = True
Else
MyBase.m_enabled = False
End If
End If
' TODO: Add other initialization code
End Sub
Public Overrides Sub OnClick()
'TODO: Add CmdFlowCreation.OnClick implementation
Dim pLayer As ILayer
Dim pFeatLayer As IFeatureLayer
Dim pFeatClass As IFeatureClass
pLineLayer = New FeatureLayer
pFeatClass = GetArcCatalogSelectedLayer()
If pFeatClass Is Nothing Then
Exit Sub
End If
pLineLayer.FeatureClass = pFeatClass
''''MyBase.m_enabled = False
GetWSFactory()
PopulateLineAngle()
End Sub
Public Function GetArcCatalogSelectedLayer() As IFeatureClass
Dim arcCatalog As IGxApplication
arcCatalog = CType(m_application, IGxApplication)
'Get the Selected Object in Catalog
Dim catalogSelectedObject As ESRI.ArcGIS.Catalog.IGxObject = arcCatalog.SelectedObject
If (Not (TypeOf catalogSelectedObject Is ESRI.ArcGIS.Catalog.IGxDataset)) Then
System.Windows.Forms.MessageBox.Show("Must have feature dataset selected")
Return Nothing
End If
'Make sure it's a Feature Class
Dim catalogDataset As IGxDataset
catalogDataset = CType(catalogSelectedObject, IGxDataset)
If (catalogDataset.Type <> esriDatasetType.esriDTFeatureClass) Then
System.Windows.Forms.MessageBox.Show("Must have feature featureclass selected")
Return Nothing
End If
Dim featureClass As IFeatureClass
featureClass = CType(catalogDataset.Dataset, IFeatureClass)
If featureClass.ShapeType <> esriGeometryType.esriGeometryPolyline Then
System.Windows.Forms.MessageBox.Show("Must have a LINE type featureclass selected")
Return Nothing
End If
Return featureClass
End Function
Public Sub GetWSFactory()
On Error Resume Next
Dim pDataset As IDataset
Dim pWorkSpace As IWorkspace
pDataset = pLineLayer.FeatureClass
pWorkSpace = pDataset.Workspace
m_pPropertySet = pWorkSpace.ConnectionProperties
If Not m_pPropertySet Is Nothing Then
m_pWSF = New ESRI.ArcGIS.DataSourcesGDB.SdeWorkspaceFactory
m_pWS = m_pWSF.Open(m_pPropertySet, 0)
End If
End Sub
Private Sub PopulateLineAngle()
'get the center point of the line segment and populate the angle if the line
Dim str As String = ""
Try
Dim pQueryFilt As IQueryFilter
Dim pFeature As IFeature
Dim pFeatCur As IFeatureCursor
Dim pLnFeatClass As IFeatureClass
Dim pPtFeatClass As IFeatureClass
Dim pStatusBar As ESRI.ArcGIS.esriSystem.IStatusBar
Dim Pi As Double
Dim pCurve As ICurve
Dim pMiddlePoint As IPoint
Dim dAngle As Double
Dim pLine As ILine
Dim pTable As ITable
Dim dLength As Double
Dim lLnCompKeyFld As Long
Dim lLnCompTypeFld As Long
Dim lCompKeyFld As Long
Dim lAngleFld As Long
Dim lCompTypeFld As Long
Dim pNewFeat As IFeature
Dim pDS As IDataset
Dim lastOID As Integer = 0
pStatusBar = m_application.StatusBar
Pi = 4 * System.Math.Atan(1)
'-------- 1. Get the point layer ---------------
pPointLayer = GetPointLayer()
lastOID = GetLastOID(pPointLayer.FeatureClass)
If pPointLayer Is Nothing Then
' MsgBox "The Update point layer does not exist!", vbCritical, "Process Halted"
Exit Sub
End If
'-------- 2. populate update fields index ----------
pPtFeatClass = pPointLayer.FeatureClass
lCompKeyFld = pPtFeatClass.FindField("CompKey")
lAngleFld = pPtFeatClass.FindField("Angle")
lCompTypeFld = pPtFeatClass.FindField("CompType")
pLnFeatClass = pLineLayer.FeatureClass
lLnCompKeyFld = pLnFeatClass.FindField("Compkey")
lLnCompTypeFld = pLnFeatClass.FindField("CompType")
'--------- 3. populate the angle for all the features in the line layer ----
''''pQueryFilt = New QueryFilter
''''pFeatCur = pLnFeatClass.Search(pQueryFilt, False)
pQueryFilt = New QueryFilter
''''''
pTable = CType(pLnFeatClass, ITable)
Dim tableSort As ITableSort = New TableSortClass()
tableSort.Table = pTable
tableSort.QueryFilter = pQueryFilt
tableSort.Fields = "OBJECTID"
pLnFeatClass = CType(pTable, IFeatureClass)
pFeatCur = pLnFeatClass.Search(pQueryFilt, False)
''''''
pFeature = pFeatCur.NextFeature
Dim iCnt As Integer = 0
Dim pWorkspaceEdit As ITransactions
pWorkspaceEdit = m_pWS
pWorkspaceEdit.StartTransaction()
Do While Not pFeature Is Nothing And iCnt < lastOID 'Loop through existing features.
iCnt += 1
pStatusBar.Message(0) = "Finding .... feature:" & pFeature.OID & " - " & iCnt.ToString
pFeature = pFeatCur.NextFeature
System.Windows.Forms.Application.DoEvents()
Loop
Do While Not pFeature Is Nothing
iCnt += 1
pStatusBar.Message(0) = "Calculating .... feature:" & pFeature.OID & " - " & iCnt.ToString
pCurve = pFeature.Shape
dLength = pCurve.Length
pMiddlePoint = New ESRI.ArcGIS.Geometry.Point
'get the middle point
pCurve.QueryPoint(esriSegmentExtension.esriNoExtension, dDistance, bAsRatio, pMiddlePoint)
'get the angle
pLine = New ESRI.ArcGIS.Geometry.Line
pCurve.QueryTangent(esriSegmentExtension.esriNoExtension, dDistance, bAsRatio, dLength, pLine)
dAngle = pLine.Angle * 360 / (2 * Pi)
dAngle = 270 + dAngle
' If dAngle < 90 Then
' dAngle = 90 - dAngle
' Else
' dAngle = 450 - dAngle
' End If
'add to point layer
pNewFeat = pPtFeatClass.CreateFeature
pNewFeat.Shape = pMiddlePoint
If lAngleFld <> -1 Then pNewFeat.Value(lAngleFld) = CLng(dAngle)
If lCompKeyFld <> -1 And lLnCompKeyFld <> -1 Then
pNewFeat.Value(lCompKeyFld) = pFeature.Value(lLnCompKeyFld)
End If
If lCompTypeFld <> -1 And lLnCompTypeFld <> -1 Then
pNewFeat.Value(lCompTypeFld) = pFeature.Value(lLnCompTypeFld)
End If
pNewFeat.Store()
pWorkspaceEdit.CommitTransaction()
pFeature = pFeatCur.NextFeature
If iCnt Mod 100 = 0 Then
System.Windows.Forms.Application.DoEvents()
End If
Loop
pStatusBar.Message(0) = "Finished!"
Catch ex As Exception
MsgBox(ex.Message + " - " + str)
m_application.StatusBar.Message(0) = "Finished with errors!"
End Try
End Sub
Private Function GetLastOID(ByVal pFClass As IFeatureClass) As Integer
'sde workspace open start a transaction to rollback if any error occurs
On Error Resume Next
Dim pWorkspaceEdit As ITransactions
pWorkspaceEdit = m_pWS
'' pWorkspaceEdit.StartTransaction()
' 'delete feature class records
'
Dim pFeatCursor As IFeatureCursor
Dim pFeature As IFeature
pFeatCursor = pFClass.Update(Nothing, False)
pFeature = pFeatCursor.NextFeature
Dim OID As Integer = 0
'
Do While pFeature Is Nothing = False
OID = pFeature.OID
pFeature = pFeatCursor.NextFeature
Loop
If OID > 0 Then '' Delete the last one, it might have been corrupted
Dim qFilter As IQueryFilter
qFilter = New QueryFilter
qFilter.WhereClause = "OBJECTID = " & OID.ToString
pFeatCursor = pFClass.Update(qFilter, False)
pFeature = pFeatCursor.NextFeature
pFeatCursor.DeleteFeature()
OID = OID - 1
End If
Return OID
End Function
Private Function GetPointLayer() As ILayer
On Error GoTo eh
Dim pFWS As IFeatureWorkspace
pFWS = m_pWS
Dim sNewFCName As String
Dim sFCName As String
sFCName = GetFeatureClassName(pLineLayer)
sNewFCName = sFCName & "_FLOW_UPDATE"
' ' Get the feature class
Dim pFeatureClass As IFeatureClass
pFeatureClass = pFWS.OpenFeatureClass(sNewFCName)
If pFeatureClass Is Nothing Then 'not exits
MsgBox("The feature class : " & sNewFCName & " does not exist, please create it first then run the tool again.")
GoTo eh
Else
''AK dont delete features. Will find the last and continue from there.
''''DeleteFeatures(pFeatureClass)
'already exists, delete all the features
' Dim pDS As IDataset
' Set pDS = pFeatureClass
' pDS.Delete
'
' Set pFeatureClass = CreateFeatureClass(sNewFCName)
End If
Dim pFeatureLayer As IFeatureLayer
pFeatureLayer = New FeatureLayer
pFeatureLayer.FeatureClass = pFeatureClass
GetPointLayer = pFeatureLayer
Exit Function
eh:
GetPointLayer = Nothing
End Function
Public Function GetFeatureClassName(ByVal pFeatLayer As IFeatureLayer) As String
Dim pDataset As IDataset
pDataset = pFeatLayer.FeatureClass
GetFeatureClassName = pDataset.Name
End Function
Private Sub DeleteFeatures(ByVal pFClass As IFeatureClass)
'sde workspace open start a transaction to rollback if any error occurs
On Error Resume Next
Dim pWorkspaceEdit As ITransactions
pWorkspaceEdit = m_pWS
pWorkspaceEdit.StartTransaction()
' 'delete feature class records
'
' Dim pFeatCursor As IFeatureCursor
' Dim pFeature As IFeature
' Set pFeatCursor = pFClass.Update(Nothing, False)
' Set pFeature = pFeatCursor.NextFeature
'
' Do While pFeature Is Nothing = False
' pFeatCursor.DeleteFeature
' Set pFeature = pFeatCursor.NextFeature
' Loop
Dim pFeatureWorkspace As IFeatureWorkspace
pFeatureWorkspace = pWorkspaceEdit
Dim t As ITable
t = pFeatureWorkspace.OpenTable(pFClass.AliasName)
t.DeleteSearchedRows(Nothing)
pWorkspaceEdit.CommitTransaction()
End Sub
End Class
Draw a flow diagram of the code; then translate that into pseudo code. Define the main variables ("containers") that you want to keep your data in. What is their relationship. Do some of them change while others are constant? Are there arrays of data?
Thinking about these things up front will really help you write clean code. And you will start your programming journey in the right direction. Most people would just start writing code.
I commend you for taking the time to ask this question. Good luck.

Categories

Resources